From ccaf3a078fd7c697863546108962e792cf414a66 Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Tue, 19 Apr 2022 23:55:42 +0300 Subject: - add 53-69 fields for Navtelecom protocol --- .../protocol/NavtelecomProtocolDecoder.java | 82 +++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 5fb3e771f..4bef62b5c 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -269,7 +269,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { position.set("freq" + (j + 2 - 35), buf.readUnsignedShortLE()); break; case 37: - position.set(Position.KEY_HOURS, buf.readUnsignedIntLE()); + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() / 60); break; case 38: case 39: @@ -295,6 +295,86 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { value = buf.readByte(); position.set(Position.PREFIX_TEMP + (j + 2 - 45), (value != 0x80) ? value : null); break; + case 53: + value = buf.readUnsignedShortLE(); + if(value == 0x7FFF){ + position.set(Position.KEY_FUEL_LEVEL + "Level", (Boolean) null); + position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); + } else if (BitUtil.check(value, 7)){ + position.set(Position.KEY_FUEL_LEVEL + "Level", BitUtil.to(value, 6)); + position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); + } + else{ + position.set(Position.KEY_FUEL_LEVEL + "Level", (Boolean) null); + position.set(Position.KEY_FUEL_LEVEL, BitUtil.to(value, 6) / 10); + } + break; + case 54: + position.set(Position.KEY_FUEL_USED, buf.readFloatLE()); + break; + case 55: + value = buf.readUnsignedShortLE(); + position.set(Position.KEY_RPM, (value != 0xFFFF) ? value : null); + break; + case 56: + value = buf.readByte(); + position.set(Position.KEY_COOLANT_TEMP, (value != 0x80) ? value : null); + break; + case 57: + position.set(Position.KEY_OBD_ODOMETER, buf.readFloatLE()); + break; + case 58: + case 59: + case 60: + case 61: + case 62: + value = buf.readUnsignedShortLE(); + position.set( + Position.KEY_AXLE_WEIGHT + (j + 2 - 58), (value != 65535) ? value : null + ); + break; + case 63: + value = buf.readUnsignedByte(); + position.set("obdAccelPos", (value != 0xFF) ? value : null); + break; + case 64: + value = buf.readUnsignedByte(); + position.set("obdBrakePos", (value != 0xFF) ? value : null); + break; + case 65: + value = buf.readUnsignedByte(); + position.set(Position.KEY_ENGINE_LOAD, (value != 0xFF) ? value : null); + break; + case 66: + value = buf.readUnsignedShortLE(); + if(value == 0x7FFF){ + position.set("obdAdBlueLevel", (Boolean) null); + position.set("obdAdBlue", (Boolean) null); + } else if (BitUtil.check(value, 7)){ + position.set("obdAdBlueLevel", BitUtil.to(value, 6)); + position.set("obdAdBlue", (Boolean) null); + } + else{ + position.set("obdAdBlueLevel", (Boolean) null); + position.set("obdAdBlue", BitUtil.to(value, 6) / 10); + } + break; + case 67: + position.set("obdHours", buf.readUnsignedIntLE() / 60); + break; + case 68: + value = buf.readUnsignedShortLE(); + position.set( + Position.KEY_ODOMETER_SERVICE, (value != 0xFFFF) ? (value * 5000) : null + ); + break; + case 69: + value = buf.readUnsignedByte(); + position.set( + Position.KEY_OBD_SPEED, + (value != 0xFF) ? UnitsConverter.knotsFromKph(value) : null + ); + break; default: buf.skipBytes(getItemLength(j + 1)); break; -- cgit v1.2.3 From 41bb8b4934ad70241f98f9cc83866fd565e79da0 Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Wed, 20 Apr 2022 23:06:21 +0300 Subject: - fix checkstyle --- .../org/traccar/protocol/NavtelecomProtocolDecoder.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 4bef62b5c..cd0c3cdcb 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -297,14 +297,13 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 53: value = buf.readUnsignedShortLE(); - if(value == 0x7FFF){ + if (value == 0x7FFF) { position.set(Position.KEY_FUEL_LEVEL + "Level", (Boolean) null); position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); - } else if (BitUtil.check(value, 7)){ + } else if (BitUtil.check(value, 7)) { position.set(Position.KEY_FUEL_LEVEL + "Level", BitUtil.to(value, 6)); position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); - } - else{ + } else { position.set(Position.KEY_FUEL_LEVEL + "Level", (Boolean) null); position.set(Position.KEY_FUEL_LEVEL, BitUtil.to(value, 6) / 10); } @@ -347,14 +346,13 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 66: value = buf.readUnsignedShortLE(); - if(value == 0x7FFF){ + if (value == 0x7FFF) { position.set("obdAdBlueLevel", (Boolean) null); position.set("obdAdBlue", (Boolean) null); - } else if (BitUtil.check(value, 7)){ + } else if (BitUtil.check(value, 7)) { position.set("obdAdBlueLevel", BitUtil.to(value, 6)); position.set("obdAdBlue", (Boolean) null); - } - else{ + } else { position.set("obdAdBlueLevel", (Boolean) null); position.set("obdAdBlue", BitUtil.to(value, 6) / 10); } -- cgit v1.2.3 From 56ff656c908b19feb2fa3dcffa48cc3bcdfe9b3b Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Thu, 21 Apr 2022 21:01:19 +0300 Subject: - used "fuelLevel" key - refactor --- .../org/traccar/protocol/NavtelecomProtocolDecoder.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index cd0c3cdcb..ecaa6cbf4 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -298,13 +298,13 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 53: value = buf.readUnsignedShortLE(); if (value == 0x7FFF) { - position.set(Position.KEY_FUEL_LEVEL + "Level", (Boolean) null); + position.set("fuelLevel", (Boolean) null); position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); } else if (BitUtil.check(value, 7)) { - position.set(Position.KEY_FUEL_LEVEL + "Level", BitUtil.to(value, 6)); + position.set("fuelLevel", BitUtil.to(value, 6)); position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); } else { - position.set(Position.KEY_FUEL_LEVEL + "Level", (Boolean) null); + position.set("fuelLevel", (Boolean) null); position.set(Position.KEY_FUEL_LEVEL, BitUtil.to(value, 6) / 10); } break; @@ -329,8 +329,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 62: value = buf.readUnsignedShortLE(); position.set( - Position.KEY_AXLE_WEIGHT + (j + 2 - 58), (value != 65535) ? value : null - ); + Position.KEY_AXLE_WEIGHT + (j + 2 - 58), (value != 65535) ? value : null); break; case 63: value = buf.readUnsignedByte(); @@ -363,15 +362,13 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 68: value = buf.readUnsignedShortLE(); position.set( - Position.KEY_ODOMETER_SERVICE, (value != 0xFFFF) ? (value * 5000) : null - ); + Position.KEY_ODOMETER_SERVICE, (value != 0xFFFF) ? (value * 5000) : null); break; case 69: value = buf.readUnsignedByte(); position.set( Position.KEY_OBD_SPEED, - (value != 0xFF) ? UnitsConverter.knotsFromKph(value) : null - ); + (value != 0xFF) ? UnitsConverter.knotsFromKph(value) : null); break; default: buf.skipBytes(getItemLength(j + 1)); -- cgit v1.2.3 From 5a46718d48e2886d7bd37acd8c52f20c5c9e18bd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 27 Jan 2023 14:23:56 -0800 Subject: Scheduled reports API --- src/main/java/org/traccar/api/resource/ReportResource.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index 6944de9cb..b85e9a857 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -16,12 +16,11 @@ */ package org.traccar.api.resource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.api.BaseResource; +import org.traccar.api.SimpleObjectResource; import org.traccar.helper.LogAction; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.model.Report; import org.traccar.model.UserRestrictions; import org.traccar.reports.EventsReportProvider; import org.traccar.reports.RouteReportProvider; @@ -54,9 +53,7 @@ import java.util.List; @Path("reports") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -public class ReportResource extends BaseResource { - - private static final Logger LOGGER = LoggerFactory.getLogger(ReportResource.class); +public class ReportResource extends SimpleObjectResource { private static final String EXCEL = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; @@ -78,6 +75,10 @@ public class ReportResource extends BaseResource { @Inject private ReportMailer reportMailer; + public ReportResource() { + super(Report.class); + } + private Response executeReport(long userId, boolean mail, ReportExecutor executor) { if (mail) { reportMailer.sendAsync(userId, executor); -- cgit v1.2.3 From 42cfe6de84f705971a638e5840d647a9e9c29c05 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 28 Jan 2023 07:49:38 -0800 Subject: Upgrade velocity engine --- build.gradle | 4 +- src/main/java/org/traccar/MainModule.java | 2 - .../java/org/traccar/helper/ServletHelperTest.java | 48 +++++----------------- 3 files changed, 13 insertions(+), 41 deletions(-) diff --git a/build.gradle b/build.gradle index 91ba2cd5c..4beab09be 100644 --- a/build.gradle +++ b/build.gradle @@ -69,8 +69,8 @@ dependencies { implementation "com.sun.mail:jakarta.mail:1.6.7" implementation "org.jxls:jxls:2.4.7" // needs upgrade (wait for jexl 4) implementation "org.jxls:jxls-poi:1.0.16" // needs upgrade (wait for jexl 4) - implementation "org.apache.velocity:velocity:1.7" // needs upgrade - implementation "org.apache.velocity:velocity-tools:2.0" // needs upgrade + implementation 'org.apache.velocity:velocity-engine-core:2.3' + implementation 'org.apache.velocity.tools:velocity-tools-generic:3.1' implementation "org.apache.commons:commons-collections4:4.4" implementation "org.mnode.ical4j:ical4j:3.2.7" implementation "org.locationtech.spatial4j:spatial4j:0.8" diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 55211d109..db66e9e5f 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -26,7 +26,6 @@ import com.google.inject.name.Names; import io.netty.util.HashedWheelTimer; import io.netty.util.Timer; import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.runtime.log.NullLogChute; import org.eclipse.jetty.util.URIUtil; import org.traccar.broadcast.BroadcastService; import org.traccar.broadcast.MulticastBroadcastService; @@ -361,7 +360,6 @@ public class MainModule extends AbstractModule { public static VelocityEngine provideVelocityEngine(Config config) { Properties properties = new Properties(); properties.setProperty("file.resource.loader.path", config.getString(Keys.TEMPLATES_ROOT) + "/"); - properties.setProperty("runtime.log.logsystem.class", NullLogChute.class.getName()); if (config.hasKey(Keys.WEB_URL)) { properties.setProperty("web.url", config.getString(Keys.WEB_URL).replaceAll("/$", "")); diff --git a/src/test/java/org/traccar/helper/ServletHelperTest.java b/src/test/java/org/traccar/helper/ServletHelperTest.java index e419b6491..55b96a41a 100644 --- a/src/test/java/org/traccar/helper/ServletHelperTest.java +++ b/src/test/java/org/traccar/helper/ServletHelperTest.java @@ -1,65 +1,39 @@ package org.traccar.helper; -import org.apache.struts.mock.MockHttpServletRequest; import org.junit.Test; -import java.util.HashMap; -import java.util.Map; +import javax.servlet.http.HttpServletRequest; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ServletHelperTest { @Test public void testRetrieveRemoteAddressProxyMultiple() { - MockRequest request = new MockRequest(); - request.setRemoteAddress("147.120.1.5"); - request.addHeader("X-FORWARDED-FOR", "231.23.45.65, 10.20.10.33, 10.20.20.34"); + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRemoteAddr()).thenReturn("147.120.1.5"); + when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65, 10.20.10.33, 10.20.20.34"); assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request)); } @Test public void testRetrieveRemoteAddressProxySingle() { - MockRequest request = new MockRequest(); - request.setRemoteAddress("147.120.1.5"); - request.addHeader("X-FORWARDED-FOR", "231.23.45.65"); + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRemoteAddr()).thenReturn("147.120.1.5"); + when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65"); assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request)); } @Test public void testRetrieveRemoteAddressNoProxy() { - MockRequest request = new MockRequest(); - request.setRemoteAddress("231.23.45.65"); + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRemoteAddr()).thenReturn("231.23.45.65"); assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request)); } - private final static class MockRequest extends MockHttpServletRequest { - - private String remoteAddress; - - private Map headers = new HashMap<>(); - - public void setRemoteAddress(String remoteAddress) { - this.remoteAddress = remoteAddress; - } - - public void addHeader(String name, String value) { - headers.put(name, value); - } - - @Override - public String getHeader(String name) { - return headers.get(name); - } - - @Override - public String getRemoteAddr() { - return remoteAddress; - } - - } - } -- cgit v1.2.3 From cd3eb2adb664a7c5278a2df124a589f6ba984c93 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 29 Jan 2023 08:08:45 -0800 Subject: Fix warning --- src/main/java/org/traccar/MainModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index db66e9e5f..ae637b455 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -359,7 +359,7 @@ public class MainModule extends AbstractModule { @Provides public static VelocityEngine provideVelocityEngine(Config config) { Properties properties = new Properties(); - properties.setProperty("file.resource.loader.path", config.getString(Keys.TEMPLATES_ROOT) + "/"); + properties.setProperty("resource.loader.file.path", config.getString(Keys.TEMPLATES_ROOT) + "/"); if (config.hasKey(Keys.WEB_URL)) { properties.setProperty("web.url", config.getString(Keys.WEB_URL).replaceAll("/$", "")); -- cgit v1.2.3 From 7df40dd7e6068c09e84080c6d47b577e51426e70 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 29 Jan 2023 08:09:04 -0800 Subject: Remove JAXB dependencies --- build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.gradle b/build.gradle index 4beab09be..0ac074f20 100644 --- a/build.gradle +++ b/build.gradle @@ -78,9 +78,6 @@ dependencies { implementation "net.java.dev.jna:jna-platform:5.12.1" implementation "com.github.jnr:jnr-posix:3.1.16" implementation "com.google.protobuf:protobuf-java:$protobufVersion" - implementation "javax.xml.bind:jaxb-api:2.3.1" - implementation "com.sun.xml.bind:jaxb-core:3.0.2" // needs upgrade - implementation "com.sun.xml.bind:jaxb-impl:3.0.2" // needs upgrade implementation "javax.activation:activation:1.1.1" implementation "com.amazonaws:aws-java-sdk-sns:1.12.349" implementation "org.apache.kafka:kafka-clients:3.3.1" -- cgit v1.2.3 From f4f1b05f8d5211476ae073d8a3c2dbd10cbcbe8a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 29 Jan 2023 09:33:16 -0800 Subject: Upgrade JXLS library --- build.gradle | 5 +++-- .../traccar/handler/ComputedAttributesHandler.java | 24 ++++++++++++---------- .../traccar/handler/ComputedAttributesTest.java | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 0ac074f20..1a904d661 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ ext { jerseyVersion = "2.37" // jersey 3 javax to jakarta jacksonVersion = "2.13.4" // same version as jersey-media-json-jackson dependency protobufVersion = "3.21.9" + jxlsVersion = "2.12.0" } sourceCompatibility = "11" @@ -67,8 +68,8 @@ dependencies { implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion" implementation "org.liquibase:liquibase-core:4.17.2" implementation "com.sun.mail:jakarta.mail:1.6.7" - implementation "org.jxls:jxls:2.4.7" // needs upgrade (wait for jexl 4) - implementation "org.jxls:jxls-poi:1.0.16" // needs upgrade (wait for jexl 4) + implementation "org.jxls:jxls:$jxlsVersion" + implementation "org.jxls:jxls-poi:$jxlsVersion" implementation 'org.apache.velocity:velocity-engine-core:2.3' implementation 'org.apache.velocity.tools:velocity-tools-generic:3.1' implementation "org.apache.commons:commons-collections4:4.4" diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 620852502..ca6c0fc74 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -26,9 +26,10 @@ import java.util.Map; import java.util.Set; import io.netty.channel.ChannelHandler; -import org.apache.commons.jexl2.JexlEngine; -import org.apache.commons.jexl2.JexlException; -import org.apache.commons.jexl2.MapContext; +import org.apache.commons.jexl3.JexlBuilder; +import org.apache.commons.jexl3.JexlEngine; +import org.apache.commons.jexl3.JexlException; +import org.apache.commons.jexl3.MapContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.BaseDataHandler; @@ -57,9 +58,10 @@ public class ComputedAttributesHandler extends BaseDataHandler { @Inject public ComputedAttributesHandler(Config config, CacheManager cacheManager) { this.cacheManager = cacheManager; - engine = new JexlEngine(); - engine.setStrict(true); - engine.setFunctions(Collections.singletonMap("math", Math.class)); + engine = new JexlBuilder() + .strict(true) + .namespaces(Collections.singletonMap("math", Math.class)) + .create(); includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); } @@ -68,13 +70,13 @@ public class ComputedAttributesHandler extends BaseDataHandler { if (includeDeviceAttributes) { Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device != null) { - for (Object key : device.getAttributes().keySet()) { - result.set((String) key, device.getAttributes().get(key)); + for (String key : device.getAttributes().keySet()) { + result.set(key, device.getAttributes().get(key)); } } } Set methods = new HashSet<>(Arrays.asList(position.getClass().getMethods())); - methods.removeAll(Arrays.asList(Object.class.getMethods())); + Arrays.asList(Object.class.getMethods()).forEach(methods::remove); for (Method method : methods) { if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { String name = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4); @@ -83,8 +85,8 @@ public class ComputedAttributesHandler extends BaseDataHandler { if (!method.getReturnType().equals(Map.class)) { result.set(name, method.invoke(position)); } else { - for (Object key : ((Map) method.invoke(position)).keySet()) { - result.set((String) key, ((Map) method.invoke(position)).get(key)); + for (Object key : ((Map) method.invoke(position)).keySet()) { + result.set((String) key, ((Map) method.invoke(position)).get(key)); } } } catch (IllegalAccessException | InvocationTargetException error) { diff --git a/src/test/java/org/traccar/handler/ComputedAttributesTest.java b/src/test/java/org/traccar/handler/ComputedAttributesTest.java index 2668c4f14..0beef9c57 100644 --- a/src/test/java/org/traccar/handler/ComputedAttributesTest.java +++ b/src/test/java/org/traccar/handler/ComputedAttributesTest.java @@ -41,7 +41,7 @@ public class ComputedAttributesTest { attribute.setExpression("(bitFlag & 4) != 0"); assertEquals(true, handler.computeAttribute(attribute, position)); - attribute.setExpression("if (event == 42) \"lowBattery\""); + attribute.setExpression("event == 42 ? \"lowBattery\" : null"); assertEquals("lowBattery", handler.computeAttribute(attribute, position)); attribute.setExpression("speed > 5 && valid"); -- cgit v1.2.3 From bcf1daf348c9a83892b1b0e214052327529d7064 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 31 Jan 2023 15:03:48 -0800 Subject: Improve test emails --- src/main/java/org/traccar/mail/LogMailManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/mail/LogMailManager.java b/src/main/java/org/traccar/mail/LogMailManager.java index b6b912d6c..4af68809c 100644 --- a/src/main/java/org/traccar/mail/LogMailManager.java +++ b/src/main/java/org/traccar/mail/LogMailManager.java @@ -38,7 +38,9 @@ public class LogMailManager implements MailManager { @Override public void sendMessage(User user, String subject, String body, MimeBodyPart attachment) throws MessagingException { - LOGGER.info("\nTo: " + user.getEmail() + "\nSubject: " + subject + "\nBody:\n" + body); + LOGGER.info( + "Email sent\nTo: {}\nSubject: {}\nAttachment: {}\nBody:\n{}", + user.getEmail(), subject, attachment != null ? attachment.getFileName() : null, body); } } -- cgit v1.2.3 From 707fccfa5b8d3afaff10f70a65e6d99ed0df6561 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 2 Feb 2023 13:42:29 -0800 Subject: Add combined report --- .../org/traccar/api/resource/ReportResource.java | 17 ++++++ .../traccar/reports/CombinedReportProvider.java | 70 ++++++++++++++++++++++ .../traccar/reports/model/CombinedReportItem.java | 54 +++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 src/main/java/org/traccar/reports/CombinedReportProvider.java create mode 100644 src/main/java/org/traccar/reports/model/CombinedReportItem.java diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index b85e9a857..e392f3f90 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -22,6 +22,7 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.Report; import org.traccar.model.UserRestrictions; +import org.traccar.reports.CombinedReportProvider; import org.traccar.reports.EventsReportProvider; import org.traccar.reports.RouteReportProvider; import org.traccar.reports.StopsReportProvider; @@ -29,6 +30,7 @@ import org.traccar.reports.SummaryReportProvider; import org.traccar.reports.TripsReportProvider; import org.traccar.reports.common.ReportExecutor; import org.traccar.reports.common.ReportMailer; +import org.traccar.reports.model.CombinedReportItem; import org.traccar.reports.model.StopReportItem; import org.traccar.reports.model.SummaryReportItem; import org.traccar.reports.model.TripReportItem; @@ -57,6 +59,9 @@ public class ReportResource extends SimpleObjectResource { private static final String EXCEL = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + @Inject + private CombinedReportProvider combinedReportProvider; + @Inject private EventsReportProvider eventsReportProvider; @@ -96,6 +101,18 @@ public class ReportResource extends SimpleObjectResource { } } + @Path("combined") + @GET + public Collection getCombined( + @QueryParam("deviceId") List deviceIds, + @QueryParam("groupId") List groupIds, + @QueryParam("from") Date from, + @QueryParam("to") Date to) throws StorageException { + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); + LogAction.logReport(getUserId(), "combined", from, to, deviceIds, groupIds); + return combinedReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); + } + @Path("route") @GET public Collection getRoute( diff --git a/src/main/java/org/traccar/reports/CombinedReportProvider.java b/src/main/java/org/traccar/reports/CombinedReportProvider.java new file mode 100644 index 000000000..ca290f7db --- /dev/null +++ b/src/main/java/org/traccar/reports/CombinedReportProvider.java @@ -0,0 +1,70 @@ +/* + * 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.reports; + +import org.traccar.helper.model.PositionUtil; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.reports.common.ReportUtils; +import org.traccar.reports.model.CombinedReportItem; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.stream.Collectors; + +public class CombinedReportProvider { + + private final ReportUtils reportUtils; + private final Storage storage; + + @Inject + public CombinedReportProvider(ReportUtils reportUtils, Storage storage) { + this.reportUtils = reportUtils; + this.storage = storage; + } + + public Collection getObjects( + long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws StorageException { + reportUtils.checkPeriodLimit(from, to); + + ArrayList result = new ArrayList<>(); + for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + CombinedReportItem item = new CombinedReportItem(); + item.setDeviceId(device.getId()); + item.setRoute(PositionUtil.getPositions(storage, device.getId(), from, to) + .stream() + .map(p -> new double[] { p.getLongitude(), p.getLatitude() }) + .collect(Collectors.toList())); + item.setEvents(storage.getObjects(Event.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", device.getId()), + new Condition.Between("eventTime", "from", from, "to", to)), + new Order("eventTime")))); + result.add(item); + } + return result; + } +} diff --git a/src/main/java/org/traccar/reports/model/CombinedReportItem.java b/src/main/java/org/traccar/reports/model/CombinedReportItem.java new file mode 100644 index 000000000..00f2cc08e --- /dev/null +++ b/src/main/java/org/traccar/reports/model/CombinedReportItem.java @@ -0,0 +1,54 @@ +/* + * 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.reports.model; + +import org.traccar.model.Event; + +import java.util.List; + +public class CombinedReportItem { + + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + + private List route; + + public List getRoute() { + return route; + } + + public void setRoute(List route) { + this.route = route; + } + + private List events; + + public List getEvents() { + return events; + } + + public void setEvents(List events) { + this.events = events; + } + +} -- cgit v1.2.3 From 47c9d9fb21e897733f7aaa29bb5797036ccc4476 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 2 Feb 2023 13:56:18 -0800 Subject: Add event positions --- .../org/traccar/reports/CombinedReportProvider.java | 18 +++++++++++++----- .../org/traccar/reports/model/CombinedReportItem.java | 11 +++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/reports/CombinedReportProvider.java b/src/main/java/org/traccar/reports/CombinedReportProvider.java index ca290f7db..d47a91bef 100644 --- a/src/main/java/org/traccar/reports/CombinedReportProvider.java +++ b/src/main/java/org/traccar/reports/CombinedReportProvider.java @@ -53,16 +53,24 @@ public class CombinedReportProvider { for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { CombinedReportItem item = new CombinedReportItem(); item.setDeviceId(device.getId()); - item.setRoute(PositionUtil.getPositions(storage, device.getId(), from, to) - .stream() - .map(p -> new double[] { p.getLongitude(), p.getLatitude() }) + var positions = PositionUtil.getPositions(storage, device.getId(), from, to); + item.setRoute(positions.stream() + .map(p -> new double[] {p.getLongitude(), p.getLatitude()}) .collect(Collectors.toList())); - item.setEvents(storage.getObjects(Event.class, new Request( + var events = storage.getObjects(Event.class, new Request( new Columns.All(), new Condition.And( new Condition.Equals("deviceId", device.getId()), new Condition.Between("eventTime", "from", from, "to", to)), - new Order("eventTime")))); + new Order("eventTime"))); + item.setEvents(events); + var eventPositions = events.stream() + .map(Event::getPositionId) + .filter(positionId -> positionId > 0) + .collect(Collectors.toSet()); + item.setPositions(positions.stream() + .filter(p -> eventPositions.contains(p.getId())) + .collect(Collectors.toList())); result.add(item); } return result; diff --git a/src/main/java/org/traccar/reports/model/CombinedReportItem.java b/src/main/java/org/traccar/reports/model/CombinedReportItem.java index 00f2cc08e..810e00916 100644 --- a/src/main/java/org/traccar/reports/model/CombinedReportItem.java +++ b/src/main/java/org/traccar/reports/model/CombinedReportItem.java @@ -16,6 +16,7 @@ package org.traccar.reports.model; import org.traccar.model.Event; +import org.traccar.model.Position; import java.util.List; @@ -51,4 +52,14 @@ public class CombinedReportItem { this.events = events; } + private List positions; + + public List getPositions() { + return positions; + } + + public void setPositions(List positions) { + this.positions = positions; + } + } -- cgit v1.2.3 From 5e690d9b586c191bc620260a2b7551d52f8d28a2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 3 Feb 2023 14:19:38 -0800 Subject: Filter no location events --- src/main/java/org/traccar/reports/CombinedReportProvider.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/reports/CombinedReportProvider.java b/src/main/java/org/traccar/reports/CombinedReportProvider.java index d47a91bef..afe146e91 100644 --- a/src/main/java/org/traccar/reports/CombinedReportProvider.java +++ b/src/main/java/org/traccar/reports/CombinedReportProvider.java @@ -63,10 +63,11 @@ public class CombinedReportProvider { new Condition.Equals("deviceId", device.getId()), new Condition.Between("eventTime", "from", from, "to", to)), new Order("eventTime"))); - item.setEvents(events); + item.setEvents(events.stream() + .filter(p -> p.getPositionId() > 0) + .collect(Collectors.toList())); var eventPositions = events.stream() .map(Event::getPositionId) - .filter(positionId -> positionId > 0) .collect(Collectors.toSet()); item.setPositions(positions.stream() .filter(p -> eventPositions.contains(p.getId())) -- cgit v1.2.3 From 7f7e5a5d479e58e83c8f0f5b81e230f1ed460478 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 3 Feb 2023 14:25:38 -0800 Subject: Fix fuel events --- src/main/java/org/traccar/handler/events/FuelEventHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/handler/events/FuelEventHandler.java b/src/main/java/org/traccar/handler/events/FuelEventHandler.java index 462cc4223..a1584d4e4 100644 --- a/src/main/java/org/traccar/handler/events/FuelEventHandler.java +++ b/src/main/java/org/traccar/handler/events/FuelEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -60,13 +60,13 @@ public class FuelEventHandler extends BaseEventHandler { if (change > 0) { double threshold = AttributeUtil.lookup( cacheManager, Keys.EVENT_FUEL_INCREASE_THRESHOLD, position.getDeviceId()); - if (change >= threshold) { + if (threshold > 0 && change >= threshold) { return Map.of(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position), position); } } else if (change < 0) { double threshold = AttributeUtil.lookup( cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId()); - if (Math.abs(change) >= threshold) { + if (threshold > 0 && Math.abs(change) >= threshold) { return Map.of(new Event(Event.TYPE_DEVICE_FUEL_DROP, position), position); } } -- cgit v1.2.3 From 74008e1053d49b407eb8eb44d7d60537bdf22047 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 3 Feb 2023 14:50:02 -0800 Subject: Exclude event types --- src/main/java/org/traccar/reports/CombinedReportProvider.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/reports/CombinedReportProvider.java b/src/main/java/org/traccar/reports/CombinedReportProvider.java index afe146e91..923fd12b4 100644 --- a/src/main/java/org/traccar/reports/CombinedReportProvider.java +++ b/src/main/java/org/traccar/reports/CombinedReportProvider.java @@ -31,10 +31,13 @@ import javax.inject.Inject; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.Set; import java.util.stream.Collectors; public class CombinedReportProvider { + private static final Set EXCLUDE_TYPES = Set.of(Event.TYPE_DEVICE_MOVING); + private final ReportUtils reportUtils; private final Storage storage; @@ -64,7 +67,7 @@ public class CombinedReportProvider { new Condition.Between("eventTime", "from", from, "to", to)), new Order("eventTime"))); item.setEvents(events.stream() - .filter(p -> p.getPositionId() > 0) + .filter(e -> e.getPositionId() > 0 && !EXCLUDE_TYPES.contains(e.getType())) .collect(Collectors.toList())); var eventPositions = events.stream() .map(Event::getPositionId) -- cgit v1.2.3 From 1e354ec746635b5773150ac4169ac7468cb227b9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 Feb 2023 07:27:20 -0800 Subject: Fix temperature decoding --- src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java index cb0e10042..db1b365c3 100644 --- a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java @@ -314,7 +314,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder { } if (buf.readableBytes() >= 12) { - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0); + position.set(Position.PREFIX_TEMP + 1, buf.readShort() / 256.0); position.set("humidity", buf.readUnsignedShort() * 0.1); position.set("illuminance", buf.readUnsignedInt() / 256.0); position.set("co2", buf.readUnsignedInt()); -- cgit v1.2.3 From 5fb56cc35f0448336100f83008b6a82b051386e6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 Feb 2023 14:13:37 -0800 Subject: Update Java dependencies --- build.gradle | 60 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/build.gradle b/build.gradle index 1a904d661..2b072f0f9 100644 --- a/build.gradle +++ b/build.gradle @@ -9,15 +9,6 @@ repositories { mavenCentral() } -ext { - guiceVersion = "5.1.0" - jettyVersion = "10.0.12" // jetty 11 javax to jakarta - jerseyVersion = "2.37" // jersey 3 javax to jakarta - jacksonVersion = "2.13.4" // same version as jersey-media-json-jackson dependency - protobufVersion = "3.21.9" - jxlsVersion = "2.12.0" -} - sourceCompatibility = "11" compileJava.options.encoding = "UTF-8" jar.destinationDirectory = file("$projectDir/target") @@ -28,27 +19,36 @@ checkstyle { checkstyleTest.enabled = false } -protobuf { - protoc { - artifact = "com.google.protobuf:protoc:$protobufVersion" - } -} - enforce { rule(enforcer.rules.EnforceBytecodeVersion) { r -> r.maxJdkVersion = "11" } } +ext { + guiceVersion = "5.1.0" + jettyVersion = "10.0.13" // jetty 11 javax to jakarta + jerseyVersion = "2.38" // jersey 3 javax to jakarta + jacksonVersion = "2.13.3" // same version as jersey-media-json-jackson dependency + protobufVersion = "3.21.12" + jxlsVersion = "2.12.0" +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:$protobufVersion" + } +} + dependencies { implementation "commons-codec:commons-codec:1.15" implementation "com.h2database:h2:2.1.214" - implementation "com.mysql:mysql-connector-j:8.0.31" - implementation "org.postgresql:postgresql:42.5.1" - implementation "com.microsoft.sqlserver:mssql-jdbc:11.2.1.jre11" + implementation "com.mysql:mysql-connector-j:8.0.32" + implementation "org.postgresql:postgresql:42.5.3" + implementation "com.microsoft.sqlserver:mssql-jdbc:12.2.0.jre11" implementation "com.zaxxer:HikariCP:5.0.1" - implementation "io.netty:netty-all:4.1.85.Final" - implementation "org.slf4j:slf4j-jdk14:2.0.5" + implementation "io.netty:netty-all:4.1.87.Final" + implementation "org.slf4j:slf4j-jdk14:2.0.6" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" @@ -66,26 +66,26 @@ dependencies { implementation "org.glassfish.hk2:guice-bridge:2.6.1" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.17.2" + implementation "org.liquibase:liquibase-core:4.19.0" implementation "com.sun.mail:jakarta.mail:1.6.7" implementation "org.jxls:jxls:$jxlsVersion" implementation "org.jxls:jxls-poi:$jxlsVersion" - implementation 'org.apache.velocity:velocity-engine-core:2.3' - implementation 'org.apache.velocity.tools:velocity-tools-generic:3.1' + implementation "org.apache.velocity:velocity-engine-core:2.3" + implementation "org.apache.velocity.tools:velocity-tools-generic:3.1" implementation "org.apache.commons:commons-collections4:4.4" - implementation "org.mnode.ical4j:ical4j:3.2.7" + implementation "org.mnode.ical4j:ical4j:3.2.8" implementation "org.locationtech.spatial4j:spatial4j:0.8" implementation "org.locationtech.jts:jts-core:1.19.0" - implementation "net.java.dev.jna:jna-platform:5.12.1" + implementation "net.java.dev.jna:jna-platform:5.13.0" implementation "com.github.jnr:jnr-posix:3.1.16" implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation "javax.activation:activation:1.1.1" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.349" - implementation "org.apache.kafka:kafka-clients:3.3.1" - implementation 'com.hivemq:hivemq-mqtt-client:1.3.0' + implementation "com.amazonaws:aws-java-sdk-sns:1.12.399" + implementation "org.apache.kafka:kafka-clients:3.3.2" + implementation "com.hivemq:hivemq-mqtt-client:1.3.0" implementation("com.google.firebase:firebase-admin:9.1.1") { - exclude group: 'com.google.cloud', module: 'google-cloud-firestore' - exclude group: 'com.google.cloud', module: 'google-cloud-storage' + exclude group: "com.google.cloud", module: "google-cloud-firestore" + exclude group: "com.google.cloud", module: "google-cloud-storage" } testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:4.+" -- cgit v1.2.3 From 250be2f49fe578b13ced80bbcf13a7b15b2f267e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 Feb 2023 15:18:21 -0800 Subject: Update version number --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 2b072f0f9..a7baaa336 100644 --- a/build.gradle +++ b/build.gradle @@ -101,7 +101,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.5", + "Implementation-Version": "5.6", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 28b33adfb..09b94ee5e 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.5 +AppVersion=5.6 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index 3eab9b522..229296c1a 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.5", + "version": "5.6", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From 38221e1a4041937f437d5f93edfdf2973c1f70b2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 Feb 2023 16:23:31 -0800 Subject: Update integration tests --- tools/test-integration.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/tools/test-integration.py b/tools/test-integration.py index 89f1c76ed..9aad642ae 100755 --- a/tools/test-integration.py +++ b/tools/test-integration.py @@ -4,7 +4,7 @@ import sys import os import xml.etree.ElementTree import urllib -import urllib2 +import urllib.request as urllib2 import json import socket import time @@ -18,10 +18,9 @@ messages = { 't55' : '$PGID,123456789012345*0F\r\n$GPRMC,120500.000,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,,*33\r\n', 'xexun' : '111111120009,+436763737552,GPRMC,120600.000,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,,,A*68,F,, imei:123456789012345,04,481.2,F:4.15V,0,139,2689,232,03,2725,0576\n', 'totem' : '$$B3123456789012345|AA$GPRMC,120700.000,A,6000.0000,N,13000.0000,E,0.00,,010112,,,A*74|01.8|01.0|01.5|000000000000|20120403234603|14251914|00000000|0012D888|0000|0.0000|3674|940B\r\n', - 'meiligao' : '$$\x00\x60\x12\x34\x56\xFF\xFF\xFF\xFF\x99\x55120900.000,A,6000.0000,N,13000.0000,E,0.00,,010112,,*1C|11.5|194|0000|0000,0000\x69\x62\x0D\x0A', 'suntech' : 'SA200STT;123456;042;20120101;12:11:00;16d41;-15.618767;-056.083214;000.011;000.00;11;1;41557;12.21;000000;1;3205\r', 'h02' : '*HQ,123456789012345,V1,121300,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,ffffffff,000000,000000,000000,000000#', - 'jt600' : '$\x00\x00\x12\x34\x56\x11\x00\x1B\x01\x01\x12\x12\x14\x00\x60\x00\x00\x00\x13\x00\x00\x00\x0F\x00\x00\x07\x50\x00\x00\x00\x2B\x91\x04\x4D\x1F\xA1', + 'jt600' : '(1234567890,P45,290322,132412,25.28217,S,57.54683,W,A,0,0,5,0,0000000000,0,0,9,0)', 'v680' : '#123456789012345#1000#0#1000#AUT#1#66830FFB#13000.0000,E,6000.0000,N,001.41,259#010112#121600##', 'pt502' : '$POS,123456,121700.000,A,6000.0000,N,13000.0000,E,0.0,0.0,010112,,,A/00000,00000/0/23895000//\r\n', 'tr20' : '%%123456789012345,A,120101121800,N6000.0000E13000.0000,0,000,0,01034802,150,[Message]\r\n', @@ -119,6 +118,9 @@ messages = { 'mobilogix': '[2020-10-25 20:45:09,T9,1,V1.2.3,123456789012,59,10.50,701,-25.236860,-45.708530,0,314]', 'swiftech': '@@123456789012345,,0,102040,1023.9670,N,07606.8160,E,2.26,151220,A,0127,1,1,03962,00000,#', 'ennfu': 'Ennfu:123456789012345,041504.00,A,3154.86654,N,11849.08737,E,0.053,,080121,20,3.72,21.4,V0.01$', + 'startek': '&&o125,123456789012345,000,0,,210702235150,A,27.263505,153.037061,11,1.2,0,0,31,5125,505|1|7032|8C89802,20,0000002D,00,00,01E2|019DF0\r\n', + 'hoopo': '{ "deviceId": "123456789012345", "assetName": "123456789012345", "assetType": "test", "eventData": { "latitude": 31.97498, "longitude": 34.80802, "locationName": "", "accuracyLevel": "High", "eventType": "Arrival", "batteryLevel": 100, "receiveTime": "2021-09-20T18:52:32Z" }, "eventTime": "2021-09-20T08:52:02Z", "serverReportTime": "0001-01-01T00:00:00Z" }', + 'techtocruz': '$$A120,123456789012345,211005105836,A,FLEX,KCB 947C,000.0,0,-1.38047,S,36.93951,E,1648.4,243.140,21,28,12.1,3.7,0,1,0,0,0,*F6', } baseUrl = 'http://localhost:8082' @@ -135,14 +137,14 @@ def load_ports(): if key.endswith('.port'): ports[key[:-5]] = int(entry.text) if debug: - print '\nports: %s\n' % repr(ports) + print('\nports: {ports!r}\n') return ports def login(): request = urllib2.Request(baseUrl + '/api/session') - response = urllib2.urlopen(request, urllib.parse.urlencode(user)) + response = urllib2.urlopen(request, urllib.parse.urlencode(user).encode()) if debug: - print '\nlogin: %s\n' % repr(json.load(response)) + print(f'\nlogin: {json.load(response)!r}\n') return response.headers.get('Set-Cookie') def remove_devices(cookie): @@ -151,7 +153,7 @@ def remove_devices(cookie): response = urllib2.urlopen(request) data = json.load(response) if debug: - print '\ndevices: %s\n' % repr(data) + print(f'\ndevices: {data!r}\n') for device in data: request = urllib2.Request(baseUrl + '/api/devices/' + str(device['id'])) request.add_header('Cookie', cookie) @@ -163,14 +165,14 @@ def add_device(cookie, unique_id): request.add_header('Cookie', cookie) request.add_header('Content-Type', 'application/json') device = { 'name' : unique_id, 'uniqueId' : unique_id } - response = urllib2.urlopen(request, json.dumps(device)) + response = urllib2.urlopen(request, json.dumps(device).encode()) data = json.load(response) return data['id'] def send_message(port, message): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', port)) - s.send(message) + s.send(message.encode('ascii')) time.sleep(0.5) s.close() @@ -203,9 +205,9 @@ if __name__ == "__main__": all = set(ports.keys()) protocols = set(messages.keys()) - print 'Total: %d' % len(all) - print 'Missing: %d' % len(all - protocols) - print 'Covered: %d' % len(protocols) + print(f'Total: {len(all)}') + print(f'Missing: {len(all - protocols)}') + print(f'Covered: {len(protocols)}') for protocol in messages: send_message(ports[protocol], messages[protocol]) @@ -213,8 +215,8 @@ if __name__ == "__main__": for device in devices: protocols -= set(get_protocols(cookie, devices[device])) - print 'Success: %d' % (len(messages) - len(protocols)) - print 'Failed: %d' % len(protocols) + print(f'Success: {len(messages) - len(protocols)}') + print(f'Failed:{len(protocols)}') if protocols: - print '\nFailed: %s' % repr(list(protocols)) + print(f'\nFailed: {list(protocols)!r}') -- cgit v1.2.3 From 5f94cba5d945f57ed78952c8eb0d743d5a392093 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 Feb 2023 07:02:24 -0800 Subject: Update release script --- .github/workflows/release.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4ceb88a7c..e4cf5dc51 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 @@ -34,7 +34,7 @@ jobs: traccar-web/package-lock.json traccar-web/modern/package-lock.json - run: | - wget -q http://cdn.sencha.com/cmd/7.1.0.15/no-jre/SenchaCmd-7.1.0.15-linux-i386.sh.zip + wget -q https://trials.sencha.com/cmd/7.6.0/SenchaCmd-7.6.0.87-linux-amd64.sh.zip unzip SenchaCmd-*.zip ./SenchaCmd-*.sh -q echo "$HOME/bin/Sencha/Cmd/" >> $GITHUB_PATH @@ -47,9 +47,9 @@ jobs: working-directory: ./setup run: | wget -q http://files.jrsoftware.org/is/5/isetup-5.5.6.exe - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4+8/OpenJDK17U-jdk_x64_windows_hotspot_17.0.4_8.zip - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4+8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.4_8.tar.gz - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4+8/OpenJDK17U-jdk_arm_linux_hotspot_17.0.4_8.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_windows_hotspot_17.0.6_10.zip + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_linux_hotspot_17.0.6_10.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_arm_linux_hotspot_17.0.6_10.tar.gz ./package.sh ${{ github.event.inputs.version }} - name: Upload installers working-directory: ./setup -- cgit v1.2.3 From 8e533cc9cc71523b699efcc0ddf4d46ac30ac389 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 Feb 2023 07:10:41 -0800 Subject: Update npm version --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e4cf5dc51..423ed2d83 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: - run: ./gradlew build - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 18 cache: npm cache-dependency-path: | traccar-web/package-lock.json -- cgit v1.2.3 From 9c6de5bea8d6220478a9885ce2e17a7ccaeb3ce3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 Feb 2023 07:21:33 -0800 Subject: Try workaround --- .github/workflows/release.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 423ed2d83..d49b3c609 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,8 +41,9 @@ jobs: - run: ./traccar-web/tools/package.sh - run: | sudo dpkg --add-architecture i386 - sudo apt-get update - sudo apt-get install innoextract makeself wine32 s3cmd + sudo dpkg -l | awk '/ii lib.*deb.sury.org/ {gsub(/:.*/, s, $2); print $2}' | xargs apt show -a | awk '/Package:/ {p=$2} /APT-Sources: .*focal\/main/ {print p"/focal"}' | sudo xargs eatmydata apt install --allow-downgrades + sudo DEBIAN_FRONTEND=noninteractive eatmydata apt install -y --no-install-recommends wine-stable wine32 + sudo apt-get install innoextract makeself s3cmd - name: Build installers working-directory: ./setup run: | -- cgit v1.2.3 From 7236387b3408525be01a4934894fafb0a65bac1f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 Feb 2023 07:30:55 -0800 Subject: Downgrade OS version --- .github/workflows/release.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d49b3c609..6eb02ad9c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 @@ -41,9 +41,8 @@ jobs: - run: ./traccar-web/tools/package.sh - run: | sudo dpkg --add-architecture i386 - sudo dpkg -l | awk '/ii lib.*deb.sury.org/ {gsub(/:.*/, s, $2); print $2}' | xargs apt show -a | awk '/Package:/ {p=$2} /APT-Sources: .*focal\/main/ {print p"/focal"}' | sudo xargs eatmydata apt install --allow-downgrades - sudo DEBIAN_FRONTEND=noninteractive eatmydata apt install -y --no-install-recommends wine-stable wine32 - sudo apt-get install innoextract makeself s3cmd + sudo apt-get update + sudo apt-get install innoextract makeself wine32 s3cmd - name: Build installers working-directory: ./setup run: | -- cgit v1.2.3 From 814fbee673d42588b53bd611128e8be1056ba883 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 Feb 2023 07:33:44 -0800 Subject: Try new version --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6eb02ad9c..0a9fb2e73 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 -- cgit v1.2.3 From 5f6ad974bec4f9c74f4464a53da0de31e7fcb10c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 Feb 2023 08:28:28 -0800 Subject: Update submodule --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 610ce1e54..091d10531 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 610ce1e5447d47c316f87887b64c4c459bad8559 +Subproject commit 091d10531a59216c5f0a812609742e097c68ff2c -- cgit v1.2.3 From 3ba077b0002481bf262a59ff2ad266b04a07c589 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 6 Feb 2023 11:32:04 -0800 Subject: Include all dependencies --- build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index a7baaa336..27ab1333b 100644 --- a/build.gradle +++ b/build.gradle @@ -83,10 +83,7 @@ dependencies { implementation "com.amazonaws:aws-java-sdk-sns:1.12.399" implementation "org.apache.kafka:kafka-clients:3.3.2" implementation "com.hivemq:hivemq-mqtt-client:1.3.0" - implementation("com.google.firebase:firebase-admin:9.1.1") { - exclude group: "com.google.cloud", module: "google-cloud-firestore" - exclude group: "com.google.cloud", module: "google-cloud-storage" - } + implementation "com.google.firebase:firebase-admin:9.1.1" testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:4.+" } -- cgit v1.2.3 From 514582dd83c4520948c03eb3fc84444e0d7f5a49 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 10 Feb 2023 17:49:45 -0800 Subject: Tramigo T24 frame decoder --- src/main/java/org/traccar/protocol/TramigoFrameDecoder.java | 4 ++-- src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java index e4c94dc77..4b0fe52b3 100644 --- a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -33,7 +33,7 @@ public class TramigoFrameDecoder extends BaseFrameDecoder { if (buf.getUnsignedByte(buf.readerIndex()) == 0x80) { length = buf.getUnsignedShortLE(buf.readerIndex() + 6); } else { - length = buf.getUnsignedShort(buf.readerIndex() + 6); + length = buf.getUnsignedShortLE(buf.readerIndex() + 1); } if (length <= buf.readableBytes()) { diff --git a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java index a093d94e9..cf997c237 100644 --- a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java @@ -10,6 +10,10 @@ public class TramigoFrameDecoderTest extends ProtocolTest { var decoder = inject(new TramigoFrameDecoder()); + verifyFrame( + binary("0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265"), + decoder.decode(null, null, binary("0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265"))); + verifyFrame( binary("8000ed2bb0009c000101bee000050b09633d925b5472616d69676f3a205472697020737461727465642c2053686f636b2053656e736f722c206174204b696e6720437265656b20526f61642d46726565746f776e205374726565742c20506f727420486172636f7572742c205269766572732c204e472c20342e37363336312c20372e30313836382c2030373a31383a333620536570203320454f46"), decoder.decode(null, null, binary("8000ed2bb0009c000101bee000050b09633d925b5472616d69676f3a205472697020737461727465642c2053686f636b2053656e736f722c206174204b696e6720437265656b20526f61642d46726565746f776e205374726565742c20506f727420486172636f7572742c205269766572732c204e472c20342e37363336312c20372e30313836382c2030373a31383a333620536570203320454f46"))); -- cgit v1.2.3 From b2824862bb72e7521a61d047235d2dc8ac4c52cd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 11 Feb 2023 09:50:21 -0800 Subject: Refactor Tramigo decoder --- .../org/traccar/protocol/TramigoFrameDecoder.java | 8 +- .../traccar/protocol/TramigoProtocolDecoder.java | 155 +++++++++++++-------- .../protocol/TramigoProtocolDecoderTest.java | 3 + 3 files changed, 104 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java index 4b0fe52b3..72cadf21a 100644 --- a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java @@ -29,11 +29,15 @@ public class TramigoFrameDecoder extends BaseFrameDecoder { return null; } + int protocol = buf.getUnsignedByte(buf.readerIndex()); + int length; - if (buf.getUnsignedByte(buf.readerIndex()) == 0x80) { + if (protocol == 0x80) { length = buf.getUnsignedShortLE(buf.readerIndex() + 6); - } else { + } else if (protocol == 0x02 || protocol == 0x04) { length = buf.getUnsignedShortLE(buf.readerIndex() + 1); + } else { + length = buf.getUnsignedShort(buf.readerIndex() + 6); } if (length <= buf.readableBytes()) { diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java index 21dd78da3..7be2cd092 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 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. @@ -29,6 +29,7 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.text.DateFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; @@ -54,28 +55,39 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; int protocol = buf.readUnsignedByte(); - boolean legacy = protocol == 0x80; + + if (protocol == 0x01) { + return decode01(channel, remoteAddress, buf); + } else if (protocol == 0x80) { + return decode80(channel, remoteAddress, buf); + } + + return null; + } + + private Position decode01(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { buf.readUnsignedByte(); // version id - int index = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); - int type = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); - buf.readUnsignedShort(); // length - buf.readUnsignedShort(); // mask - buf.readUnsignedShort(); // checksum - long id = legacy ? buf.readUnsignedInt() : buf.readUnsignedIntLE(); - buf.readUnsignedInt(); // time + int index = buf.readUnsignedShortLE(); + int type = buf.readUnsignedShortLE(); - Position position = new Position(getProtocolName()); - position.set(Position.KEY_INDEX, index); - position.setValid(true); + if (type == MSG_COMPACT || type == MSG_FULL) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); + buf.readUnsignedShort(); // length + buf.readUnsignedShort(); // mask + buf.readUnsignedShort(); // checksum + long id = buf.readUnsignedIntLE(); + buf.readUnsignedInt(); // time - if (protocol == 0x01 && (type == MSG_COMPACT || type == MSG_FULL)) { + Position position = new Position(getProtocolName()); + position.set(Position.KEY_INDEX, index); + position.setValid(true); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); // need to send ack? @@ -105,56 +117,79 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { return position; - } else if (legacy) { + } - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress)); - } + return null; - String sentence = buf.toString(StandardCharsets.US_ASCII); + } - Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)"); - Matcher matcher = pattern.matcher(sentence); - if (!matcher.find()) { - return null; - } - position.setLatitude(Double.parseDouble(matcher.group(1))); - position.setLongitude(Double.parseDouble(matcher.group(2))); - - pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h"); - matcher = pattern.matcher(sentence); - if (matcher.find()) { - for (int i = 0; i < DIRECTIONS.length; i++) { - if (matcher.group(1).equals(DIRECTIONS[i])) { - position.setCourse(i * 45.0); - break; - } - } - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2)))); - } + private Position decode80(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws ParseException { - pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})"); - matcher = pattern.matcher(sentence); - if (!matcher.find()) { - return null; - } - DateFormat dateFormat = new SimpleDateFormat( - matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH); - position.setTime(DateUtil.correctYear( - dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR)))); - - if (sentence.contains("Ignition on detected")) { - position.set(Position.KEY_IGNITION, true); - } else if (sentence.contains("Ignition off detected")) { - position.set(Position.KEY_IGNITION, false); - } + buf.readUnsignedByte(); // version id + int index = buf.readUnsignedShort(); + buf.readUnsignedShort(); // type - return position; + buf.readUnsignedShort(); // length + buf.readUnsignedShort(); // mask + buf.readUnsignedShort(); // checksum + long id = buf.readUnsignedInt(); + buf.readUnsignedInt(); // time + + Position position = new Position(getProtocolName()); + position.set(Position.KEY_INDEX, index); + position.setValid(true); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress)); } - return null; + String sentence = buf.toString(StandardCharsets.US_ASCII); + + Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)"); + Matcher matcher = pattern.matcher(sentence); + if (!matcher.find()) { + return null; + } + position.setLatitude(Double.parseDouble(matcher.group(1))); + position.setLongitude(Double.parseDouble(matcher.group(2))); + + pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h"); + matcher = pattern.matcher(sentence); + if (matcher.find()) { + for (int i = 0; i < DIRECTIONS.length; i++) { + if (matcher.group(1).equals(DIRECTIONS[i])) { + position.setCourse(i * 45.0); + break; + } + } + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2)))); + } + + pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})"); + matcher = pattern.matcher(sentence); + if (!matcher.find()) { + return null; + } + DateFormat dateFormat = new SimpleDateFormat( + matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH); + position.setTime(DateUtil.correctYear( + dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR)))); + + if (sentence.contains("Ignition on detected")) { + position.set(Position.KEY_IGNITION, true); + } else if (sentence.contains("Ignition off detected")) { + position.set(Position.KEY_IGNITION, false); + } + + return position; + } } diff --git a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java index c2d13d199..db3c5c32f 100644 --- a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class TramigoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TramigoProtocolDecoder(null)); + verifyNull(decoder, binary( + "0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265")); + verifyAttributes(decoder, binary( "8000c426b000a6000101c557037598050d5c8a595472616d69676f3a204d6f76696e672c20302e3132206b6d2045206f66204c617275742054696e2049736c616d6963205072696d617279205363686f6f6c2c2054616970696e672c20506572616b2c204d592c20342e38333134392c203130302e37333038352c204e572077697468207370656564203130206b6d2f682c2030303a34393a30382041756720392020454f46")); -- cgit v1.2.3 From f4b97f7aa63ce5facd4ce02bb0c16d17c3e39b74 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 11 Feb 2023 10:40:00 -0800 Subject: Tramigo M2Mv2 implementation --- .../traccar/protocol/TramigoProtocolDecoder.java | 106 ++++++++++++++++++--- .../protocol/TramigoProtocolDecoderTest.java | 4 +- 2 files changed, 96 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java index 7be2cd092..1296929bc 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BitUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -43,9 +44,6 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - public static final int MSG_COMPACT = 0x0100; - public static final int MSG_FULL = 0x00FE; - private static final String[] DIRECTIONS = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; @Override @@ -58,6 +56,8 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { if (protocol == 0x01) { return decode01(channel, remoteAddress, buf); + } else if (protocol == 0x04) { + return decode04(channel, remoteAddress, buf); } else if (protocol == 0x80) { return decode80(channel, remoteAddress, buf); } @@ -71,7 +71,7 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { int index = buf.readUnsignedShortLE(); int type = buf.readUnsignedShortLE(); - if (type == MSG_COMPACT || type == MSG_FULL) { + if (type == 0x0100 || type == 0x00FE) { buf.readUnsignedShort(); // length buf.readUnsignedShort(); // mask @@ -79,21 +79,21 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { long id = buf.readUnsignedIntLE(); buf.readUnsignedInt(); // time - Position position = new Position(getProtocolName()); - position.set(Position.KEY_INDEX, index); - position.setValid(true); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); if (deviceSession == null) { return null; } + + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_INDEX, index); // need to send ack? buf.readUnsignedShortLE(); // report trigger buf.readUnsignedShortLE(); // state flag + position.setValid(true); position.setLatitude(buf.readUnsignedIntLE() * 0.0000001); position.setLongitude(buf.readUnsignedIntLE() * 0.0000001); @@ -123,6 +123,88 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { } + private Position decode04(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws ParseException { + + buf.readUnsignedShortLE(); // length + buf.readUnsignedShortLE(); // checksum + int index = buf.readUnsignedShortLE(); + + String id = String.format("%08d%07d", buf.readUnsignedIntLE(), buf.readUnsignedIntLE()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_INDEX, index); + + position.setDeviceTime(new Date(buf.readUnsignedIntLE() * 1000)); + + while (buf.isReadable()) { + int type = buf.readUnsignedByte(); + switch (type) { + case 0: + position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); + buf.readUnsignedIntLE(); // event data + + int status = buf.readUnsignedShortLE(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 5)); + position.set(Position.KEY_STATUS, status); + + position.setValid(true); + position.setLatitude(buf.readInt() * 0.00001); + position.setLongitude(buf.readInt() * 0.00001); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_GPS, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShortLE()); + position.set("maxAcceleration", buf.readUnsignedShortLE() * 0.001); + position.set("maxDeceleration", buf.readUnsignedShortLE() * 0.001); + buf.readUnsignedShortLE(); // bearing to landmark + buf.readUnsignedIntLE(); // distance to landmark + + position.setFixTime(new Date(buf.readUnsignedIntLE() * 1000)); + + buf.readUnsignedByte(); // reserved + break; + case 1: + buf.skipBytes(buf.readUnsignedShortLE()); // landmark + break; + case 4: + buf.skipBytes(53); // trip + break; + case 20: + buf.skipBytes(32); // extended + break; + case 22: + buf.readUnsignedByte(); // zone flag + buf.skipBytes(buf.readUnsignedShortLE()); // zone name + break; + case 30: + buf.skipBytes(79); // system status + break; + case 40: + buf.skipBytes(40); // analog + break; + case 50: + buf.skipBytes(buf.readUnsignedShortLE()); // console + break; + case 255: + buf.skipBytes(4); // acknowledgement + break; + default: + throw new IllegalArgumentException(String.format("Unknown type %d", type)); + } + } + + return position.getValid() ? position : null; + + } + private Position decode80(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws ParseException { buf.readUnsignedByte(); // version id @@ -135,15 +217,14 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { long id = buf.readUnsignedInt(); buf.readUnsignedInt(); // time - Position position = new Position(getProtocolName()); - position.set(Position.KEY_INDEX, index); - position.setValid(true); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); if (deviceSession == null) { return null; } + + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_INDEX, index); if (channel != null) { channel.writeAndFlush(new NetworkMessage( @@ -159,6 +240,7 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { } position.setLatitude(Double.parseDouble(matcher.group(1))); position.setLongitude(Double.parseDouble(matcher.group(2))); + position.setValid(true); pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h"); matcher = pattern.matcher(sentence); diff --git a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java index db3c5c32f..fdef8ce19 100644 --- a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java @@ -10,8 +10,8 @@ public class TramigoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TramigoProtocolDecoder(null)); - verifyNull(decoder, binary( - "0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265")); + /*verifyNull(decoder, binary( + "0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265"));*/ verifyAttributes(decoder, binary( "8000c426b000a6000101c557037598050d5c8a595472616d69676f3a204d6f76696e672c20302e3132206b6d2045206f66204c617275742054696e2049736c616d6963205072696d617279205363686f6f6c2c2054616970696e672c20506572616b2c204d592c20342e38333134392c203130302e37333038352c204e572077697468207370656564203130206b6d2f682c2030303a34393a30382041756720392020454f46")); -- cgit v1.2.3 From 02d073d6900c401f83493380df3093d72f4d5cf2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 11 Feb 2023 14:27:47 -0800 Subject: Improve security filter --- .../traccar/api/security/SecurityRequestFilter.java | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index 94b6bbf05..9992d49e7 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -42,13 +42,6 @@ public class SecurityRequestFilter implements ContainerRequestFilter { private static final Logger LOGGER = LoggerFactory.getLogger(SecurityRequestFilter.class); - public static final String AUTHORIZATION_HEADER = "Authorization"; - public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; - public static final String BASIC_REALM = "Basic realm=\"api\""; - public static final String BEARER_PREFIX = "Bearer "; - public static final String X_REQUESTED_WITH = "X-Requested-With"; - public static final String XML_HTTP_REQUEST = "XMLHttpRequest"; - public static String[] decodeBasicAuth(String auth) { auth = auth.replaceFirst("[B|b]asic ", ""); byte[] decodedBytes = DataConverter.parseBase64(auth); @@ -81,13 +74,13 @@ public class SecurityRequestFilter implements ContainerRequestFilter { try { - String authHeader = requestContext.getHeaderString(AUTHORIZATION_HEADER); + String authHeader = requestContext.getHeaderString("Authorization"); if (authHeader != null) { try { User user; - if (authHeader.startsWith(BEARER_PREFIX)) { - user = loginService.login(authHeader.substring(BEARER_PREFIX.length())); + if (authHeader.startsWith("Bearer ")) { + user = loginService.login(authHeader.substring(7)); } else { String[] auth = decodeBasicAuth(authHeader); user = loginService.login(auth[0], auth[1]); @@ -120,8 +113,9 @@ public class SecurityRequestFilter implements ContainerRequestFilter { Method method = resourceInfo.getResourceMethod(); if (!method.isAnnotationPresent(PermitAll.class)) { Response.ResponseBuilder responseBuilder = Response.status(Response.Status.UNAUTHORIZED); - if (!XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH))) { - responseBuilder.header(WWW_AUTHENTICATE, BASIC_REALM); + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("text/html")) { + responseBuilder.header("WWW-Authenticate", "Basic realm=\"api\""); } throw new WebApplicationException(responseBuilder.build()); } -- cgit v1.2.3 From 33af2928a581eba6a1ba580b5da051612c7b7860 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 13 Feb 2023 17:20:39 -0800 Subject: Meitrack K211G extend support --- .../java/org/traccar/protocol/MeitrackProtocolDecoder.java | 12 +++++++++++- .../org/traccar/protocol/MeitrackProtocolDecoderTest.java | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 343141dca..a7accf0f1 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -510,6 +510,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x0D: position.set("runtime", buf.readUnsignedIntLE()); break; + case 0x25: + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE())); + break; case 0xA0: position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE() * 0.001); break; @@ -624,6 +627,13 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { photo = Unpooled.buffer(); requestPhotoPacket(channel, remoteAddress, imei, "camera_picture.jpg", 0); return null; + case "D82": + Position position = new Position(getProtocolName()); + position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId()); + getLastLocation(position, null); + String result = buf.toString(index + 1, buf.writerIndex() - index - 4, StandardCharsets.US_ASCII); + position.set(Position.KEY_RESULT, result); + return position; case "CCC": return decodeBinaryC(channel, remoteAddress, buf); case "CCE": diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index ce0a1e922..407d7a9b6 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -11,6 +11,13 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "$$u28,864606044993987,D82,0*D6"), + Position.KEY_RESULT, "D82,0"); + + verifyPositions(decoder, binary( + "24245B3139312C3836343630363034343939333938372C4343452C010000000200500013000601250500060007111B00470206080000093E000AE7030B0000199E011A850306028D7A570103F35ACC0604F9D06C2B0CB92E00000D3FA40C00250CA2B900010E0CCC010000B6276313000000004B00120006012A0500060007111B00470206080000093E000AE7030B0000199E011A7C0305028D7A570103F35ACC0604F9D06C2B0CB92E00000D3FA40C00010E0CCC010000B6276313000000002A31340D0A")); + verifyPositions(decoder, binary( "24246a3138312c3836343238313034313930383330332c4343452c00000000010093001f000505000600070714001502090800000900000a00000b0000160a001706001904001ad90440230006023279570103305ccc0604f536492b0c510300000d495701001c014000000b0e0ccc010000922781abb90c00002a030034212b03008b082c030053082d03009e082e030034212f030034213003003421310300342149090400000000000000004b07010104574946492a36310d0a")); -- cgit v1.2.3 From 782fd787d14bd041c818e25b06f5ebe844854163 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 14 Feb 2023 09:08:14 -0800 Subject: Tramigo T24 M2MV2 support --- src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java | 8 ++++---- .../java/org/traccar/protocol/TramigoProtocolDecoderTest.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java index 1296929bc..ddd669b36 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java @@ -153,8 +153,8 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_STATUS, status); position.setValid(true); - position.setLatitude(buf.readInt() * 0.00001); - position.setLongitude(buf.readInt() * 0.00001); + position.setLatitude(buf.readIntLE() * 0.00001); + position.setLongitude(buf.readIntLE() * 0.00001); position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); position.setCourse(buf.readUnsignedShortLE()); @@ -172,7 +172,7 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // reserved break; case 1: - buf.skipBytes(buf.readUnsignedShortLE()); // landmark + buf.skipBytes(buf.readUnsignedShortLE() - 3); // landmark break; case 4: buf.skipBytes(53); // trip @@ -191,7 +191,7 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(40); // analog break; case 50: - buf.skipBytes(buf.readUnsignedShortLE()); // console + buf.skipBytes(buf.readUnsignedShortLE() - 3); // console break; case 255: buf.skipBytes(4); // acknowledgement diff --git a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java index fdef8ce19..d692a41d5 100644 --- a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java @@ -10,8 +10,8 @@ public class TramigoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TramigoProtocolDecoder(null)); - /*verifyNull(decoder, binary( - "0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265"));*/ + verifyPosition(decoder, binary( + "0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265")); verifyAttributes(decoder, binary( "8000c426b000a6000101c557037598050d5c8a595472616d69676f3a204d6f76696e672c20302e3132206b6d2045206f66204c617275742054696e2049736c616d6963205072696d617279205363686f6f6c2c2054616970696e672c20506572616b2c204d592c20342e38333134392c203130302e37333038352c204e572077697468207370656564203130206b6d2f682c2030303a34393a30382041756720392020454f46")); -- cgit v1.2.3 From 9ceecf357132989390e8bb18160338b27539eaaa Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 14 Feb 2023 15:11:07 -0800 Subject: Refactor Totem decoder --- .../org/traccar/protocol/TotemProtocolDecoder.java | 123 +++++++++++++-------- 1 file changed, 77 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java index 9d0d794f8..fc3dce86f 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -135,7 +135,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN4 = new PatternBuilder() .text("$$") // header .number("dddd") // length - .number("(xx)") // type + .number("xx") // type .number("(d+)|") // imei .number("(x{8})") // status .number("(dd)(dd)(dd)") // date (yymmdd) @@ -257,7 +257,20 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { } } - private boolean decode12(Position position, Parser parser, Pattern pattern) { + private Position decode12(Channel channel, SocketAddress remoteAddress, String sentence, Pattern pattern) { + + Parser parser = new Parser(pattern, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); if (parser.hasNext()) { position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); @@ -283,7 +296,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { year = parser.nextInt(0); } if (year == 0) { - return false; // ignore invalid data + return null; // ignore invalid data } dateBuilder.setDate(year, month, day); position.setTime(dateBuilder.getDate()); @@ -331,10 +344,23 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, parser.next()); position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); - return true; + return position; } - private boolean decode3(Position position, Parser parser) { + private Position decode3(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN3, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); if (parser.hasNext()) { position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); @@ -363,10 +389,27 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); - return true; + return position; } - private boolean decode4(Position position, Parser parser) { + private Position decode4(Channel channel, SocketAddress remoteAddress, String sentence) { + + int type = Integer.parseInt(sentence.substring(6, 8), 16); + + Parser parser = new Parser(PATTERN4, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_ALARM, decodeAlarm4(type)); long status = parser.nextHexLong(); @@ -427,10 +470,23 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); - return true; + return position; } - private boolean decodeObd(Position position, Parser parser) { + private Position decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_OBD, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); position.setValid(true); position.setTime(parser.nextDateTime()); @@ -451,7 +507,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_THROTTLE, parser.nextInt()); position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - return true; + return position; } @Override @@ -459,50 +515,25 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { String sentence = (String) msg; - Pattern pattern = PATTERN3; + + Position position; if (sentence.contains("$Cloud")) { - pattern = PATTERN_OBD; + position = decodeObd(channel, remoteAddress, sentence); } else if (sentence.charAt(2) == '0') { - pattern = PATTERN4; + position = decode4(channel, remoteAddress, sentence); } else if (sentence.contains("$GPRMC")) { - pattern = PATTERN1; + position = decode12(channel, remoteAddress, sentence, PATTERN1); } else { int index = sentence.indexOf('|'); if (index != -1 && sentence.indexOf('|', index + 1) != -1) { - pattern = PATTERN2; + position = decode12(channel, remoteAddress, sentence, PATTERN2); + } else { + position = decode3(channel, remoteAddress, sentence); } } - Parser parser = new Parser(pattern, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - if (pattern == PATTERN4) { - position.set(Position.KEY_ALARM, decodeAlarm4(parser.nextHexInt())); - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - boolean result; - if (pattern == PATTERN1 || pattern == PATTERN2) { - result = decode12(position, parser, pattern); - } else if (pattern == PATTERN3) { - result = decode3(position, parser); - } else if (pattern == PATTERN4) { - result = decode4(position, parser); - } else { - result = decodeObd(position, parser); - } - if (channel != null) { - if (pattern == PATTERN4) { + if (sentence.charAt(2) == '0') { String response = "$$0014AA" + sentence.substring(sentence.length() - 6, sentence.length() - 2); response += String.format("%02X", Checksum.xor(response)).toUpperCase(); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); @@ -511,7 +542,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { } } - return result ? position : null; + return position; } } -- cgit v1.2.3 From a722658e5a3c2c15ceffa51a80b63bda758264bd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 14 Feb 2023 15:18:44 -0800 Subject: Decode AT07 RFID data --- .../org/traccar/protocol/TotemProtocolDecoder.java | 58 +++++++++++++++++++--- .../traccar/protocol/TotemProtocolDecoderTest.java | 5 ++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java index fc3dce86f..6f039c324 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java @@ -176,7 +176,21 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); - private static final Pattern PATTERN_OBD = new PatternBuilder() + private static final Pattern PATTERN_E2 = new PatternBuilder() + .text("$$") // header + .number("dddd") // length + .number("xx") // type + .number("(d+)|") // imei + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .expression("(.+)") // rfid + .number("|xx") // checksum + .any() + .compile(); + + private static final Pattern PATTERN_E5 = new PatternBuilder() .text("$$") // header .number("dddd") // length .number("xx") // type @@ -396,6 +410,15 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { int type = Integer.parseInt(sentence.substring(6, 8), 16); + switch (type) { + case 0xE2: + return decodeE2(channel, remoteAddress, sentence); + case 0xE5: + return decodeE5(channel, remoteAddress, sentence); + default: + break; + } + Parser parser = new Parser(PATTERN4, sentence); if (!parser.matches()) { return null; @@ -473,9 +496,34 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { return position; } - private Position decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { + private Position decodeE2(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_E2, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(parser.nextDateTime()); + position.setLongitude(parser.nextDouble()); + position.setLatitude(parser.nextDouble()); + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + return position; + } + + private Position decodeE5(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_OBD, sentence); + Parser parser = new Parser(PATTERN_E5, sentence); if (!parser.matches()) { return null; } @@ -517,9 +565,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { String sentence = (String) msg; Position position; - if (sentence.contains("$Cloud")) { - position = decodeObd(channel, remoteAddress, sentence); - } else if (sentence.charAt(2) == '0') { + if (sentence.charAt(2) == '0') { position = decode4(channel, remoteAddress, sentence); } else if (sentence.contains("$GPRMC")) { position = decode12(channel, remoteAddress, sentence, PATTERN1); diff --git a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java index df5734568..1e432bd9e 100644 --- a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class TotemProtocolDecoderTest extends ProtocolTest { @@ -10,6 +11,10 @@ public class TotemProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TotemProtocolDecoder(null)); + verifyAttribute(decoder, text( + "$$0494E2123456789012345|150425223945,113.925525,22.55814,1122334455|38"), + Position.KEY_DRIVER_UNIQUE_ID, "1122334455"); + verifyPosition(decoder, text( "$$0111AA353081090067318|0804400022070722520240400005B364ED5003107300001.700000002245.3919N10231.6952W000001860E")); -- cgit v1.2.3 From d3291d6a7dc5d7ead326f27e97a841682a3aa20f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 14 Feb 2023 15:26:46 -0800 Subject: Add missing JDK module --- setup/package.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/package.sh b/setup/package.sh index 71b86014f..f17b5fb14 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -120,7 +120,7 @@ package_other () { package_windows () { info "Building Windows 64 installer" unzip -q OpenJDK*64_windows*.zip - jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec --output out/jre + jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec,jdk.unsupported --output out/jre rm -rf jdk-* wine app/ISCC.exe traccar.iss >/dev/null rm -rf out/jre @@ -134,7 +134,7 @@ package_linux () { cp traccar.service out tar -xf OpenJDK*$1_linux*.tar.gz - jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec --output out/jre + jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec,jdk.unsupported --output out/jre rm -rf jdk-* makeself --needroot --quiet --notemp out traccar.run "traccar" ./setup.sh rm -rf out/jre -- cgit v1.2.3 From 2b046d6932a6bc0052a689d1c9ae27b51a48cac8 Mon Sep 17 00:00:00 2001 From: AuroraRAS Date: Wed, 15 Feb 2023 21:45:20 +0800 Subject: Append items in gitignore for VSCode IDE Ignore "bin" folder for ".class" files Ignore ".vscode" folder for VSCode IDE config Signed-off-by: AuroraRAS --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index c005ef9e4..2d03a9625 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ nbactions.xml .gradle out build +.vscode +bin -- cgit v1.2.3 From 596036dc3380e0750d27c814a4d3bb94f4c7e1ea Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 17 Feb 2023 06:54:24 -0800 Subject: Add another Tramigo sample --- src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java index d692a41d5..32bc05e23 100644 --- a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class TramigoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TramigoProtocolDecoder(null)); + verifyNull(decoder, binary( + "04d000a9e45c1b69101a023ef34f00549eec63047795ec63000000004eff5c0062c2e4ffbf612f00ce9aec63000000007700960180c0e4ff5f542f004c1200007b004a023d0200000001430000000000000000001f000b0006005a57436f63612d436f6c6120426f74746c696e6720506c616e74204861726172654772616e69746573696465486172617265014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265")); + verifyPosition(decoder, binary( "0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265")); -- cgit v1.2.3 From ec2b7b64a83aa1c3dcd0cd69c1ae7b2d0d8a7864 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 17 Feb 2023 08:16:37 -0800 Subject: Support GL600 frames --- src/main/java/org/traccar/protocol/Jt600FrameDecoder.java | 2 +- src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java | 8 ++++---- src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java | 8 ++++++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java index bfefb94a7..f7890f814 100644 --- a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java +++ b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java @@ -35,7 +35,7 @@ public class Jt600FrameDecoder extends BaseFrameDecoder { char type = (char) buf.getByte(buf.readerIndex()); if (type == '$') { - boolean longFormat = Jt600ProtocolDecoder.isLongFormat(buf, buf.readerIndex() + 1); + boolean longFormat = Jt600ProtocolDecoder.isLongFormat(buf); int length = buf.getUnsignedShort(buf.readerIndex() + (longFormat ? 8 : 7)) + 10; if (length <= buf.readableBytes()) { return buf.readRetainedSlice(length); diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java index 9ed44f565..dc763dea7 100644 --- a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java @@ -86,8 +86,8 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { } - static boolean isLongFormat(ByteBuf buf, int flagIndex) { - return buf.getUnsignedByte(flagIndex) >> 4 >= 7; + static boolean isLongFormat(ByteBuf buf) { + return buf.getUnsignedByte(buf.readerIndex() + 8) == 0; } static void decodeBinaryLocation(ByteBuf buf, Position position) { @@ -123,9 +123,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { List positions = new LinkedList<>(); - buf.readByte(); // header + boolean longFormat = isLongFormat(buf); - boolean longFormat = isLongFormat(buf, buf.readerIndex()); + buf.readByte(); // header String id = String.valueOf(Long.parseLong(ByteBufUtil.hexDump(buf.readSlice(5)))); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); diff --git a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java index 8e408e50f..895a0b07b 100644 --- a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java @@ -10,6 +10,14 @@ public class Jt600FrameDecoderTest extends ProtocolTest { var decoder = inject(new Jt600FrameDecoder()); + verifyFrame( + binary("2460201102320112003401010000000422434199114158229e000000000009000000000010e06400000000000020100e0868817043592664000000000000"), + decoder.decode(null, null, binary("2460201102320112003401010000000422434199114158229e000000000009000000000010e06400000000000020100e0868817043592664000000000000"))); + + verifyFrame( + binary("24657060730131001b13111710361906538525079524797f000000000000000003f300036c"), + decoder.decode(null, null, binary("24657060730131001b13111710361906538525079524797f000000000000000003f300036c"))); + verifyFrame( binary("2480413009781914003406102107544354193631006213423b00000000006c070000000020e064f91ea0671d00020f0f0f0f0f0f0f0f0f0f07f100ea0f6e"), decoder.decode(null, null, binary("2480413009781914003406102107544354193631006213423b00000000006c070000000020e064f91ea0671d00020f0f0f0f0f0f0f0f0f0f07f100ea0f6e"))); -- cgit v1.2.3 From 8ae0436e5edb76243e59ee6e9b2c1a6132fd9464 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Feb 2023 13:56:32 -0800 Subject: Fix Queclink GL53MG decoding --- src/main/java/org/traccar/helper/Parser.java | 11 +++++++++++ .../java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java | 2 +- .../java/org/traccar/protocol/StartekProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/WialonProtocolDecoder.java | 2 +- .../org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/helper/Parser.java b/src/main/java/org/traccar/helper/Parser.java index aa39e1ad7..c2aea28fa 100644 --- a/src/main/java/org/traccar/helper/Parser.java +++ b/src/main/java/org/traccar/helper/Parser.java @@ -48,6 +48,17 @@ public class Parser { } public boolean hasNext(int number) { + for (int i = position; i < position + number; i++) { + String value = matcher.group(i); + if (value == null || value.isEmpty()) { + position += number; + return false; + } + } + return true; + } + + public boolean hasNextAny(int number) { for (int i = position; i < position + number; i++) { String value = matcher.group(i); if (value != null && !value.isEmpty()) { diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 517499f02..28308ab77 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -956,7 +956,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, power * 0.001); } - if (parser.hasNext(12)) { + if (parser.hasNextAny(12)) { position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); position.set(Position.KEY_HOURS, parseHours(parser.next())); diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java index 28efa3c30..d1c35b478 100644 --- a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java @@ -225,7 +225,7 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { getConfig(), parser.nextHexInt(0), parser.nextHexInt(0)))); } - if (parser.hasNext(20)) { + if (parser.hasNextAny(20)) { String utcHours = parser.next(); String utcMinutes = parser.next(); diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java index 8e3624cb5..d75da7fbd 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -221,7 +221,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { } } - if (parser.hasNext(6)) { + if (parser.hasNextAny(6)) { position.set(Position.KEY_RPM, parser.nextInt()); position.set(Position.KEY_ENGINE_LOAD, parser.nextInt()); position.set("airFlow", parser.nextInt()); diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index 3d57525b7..b87ba2b53 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -101,7 +101,7 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { position.setTime(new Date()); } - if (parser.hasNext(9)) { + if (parser.hasNextAny(9)) { position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index f3a77228c..5696353c4 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyPositions(decoder, false, buffer( + "+BUFF:GTFRI,2E0503,861106050005423,,,0,1,,,,,,,,,,,,0,0,,98,1,0,,,20200101000001,0083$")); + verifyAttribute(decoder, buffer( "+RESP:GTERI,271002,863457051562823,,00000002,,10,1,1,0.0,15,28.2,-58.695253,-34.625413,20230119193305,0722,0007,1168,16B3BB,00,0.0,,,,99,210100,2,1,28F8A149F69A3C25,1,0190,20230119193314,07C7$"), Position.PREFIX_TEMP + 1, 25.0); -- cgit v1.2.3 From 1439422c6f4ce947f6719743b37fa49f251fc97f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Feb 2023 11:30:26 -0800 Subject: Refactor notificator classes --- setup/default.xml | 2 +- .../traccar/api/resource/NotificationResource.java | 4 +-- .../org/traccar/database/NotificationManager.java | 4 +-- .../traccar/notification/NotificatorManager.java | 12 +++----- .../java/org/traccar/notificators/Notificator.java | 5 ++-- .../traccar/notificators/NotificatorFirebase.java | 8 ++--- .../org/traccar/notificators/NotificatorMail.java | 5 ++-- .../org/traccar/notificators/NotificatorNull.java | 34 ---------------------- .../traccar/notificators/NotificatorPushover.java | 5 ++-- .../org/traccar/notificators/NotificatorSms.java | 5 ++-- .../traccar/notificators/NotificatorTelegram.java | 5 ++-- .../traccar/notificators/NotificatorTraccar.java | 18 ++++++------ .../org/traccar/notificators/NotificatorWeb.java | 8 ++--- src/main/java/org/traccar/sms/HttpSmsClient.java | 4 +-- src/main/java/org/traccar/sms/SmsManager.java | 3 +- 15 files changed, 44 insertions(+), 78 deletions(-) delete mode 100644 src/main/java/org/traccar/notificators/NotificatorNull.java diff --git a/setup/default.xml b/setup/default.xml index c00d29384..75acf25a1 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -32,7 +32,7 @@ ./media - web,mail + web,mail,command https://www.traccar.org/analytics/ diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java index 2e4ad12f3..d58557601 100644 --- a/src/main/java/org/traccar/api/resource/NotificationResource.java +++ b/src/main/java/org/traccar/api/resource/NotificationResource.java @@ -83,7 +83,7 @@ public class NotificationResource extends ExtendedObjectResource { public Response testMessage() throws MessageException, InterruptedException, StorageException { User user = permissionsService.getUser(getUserId()); for (Typed method : notificatorManager.getAllNotificatorTypes()) { - notificatorManager.getNotificator(method.getType()).send(user, new Event("test", 0), null); + notificatorManager.getNotificator(method.getType()).send(null, user, new Event("test", 0), null); } return Response.noContent().build(); } @@ -93,7 +93,7 @@ public class NotificationResource extends ExtendedObjectResource { public Response testMessage(@PathParam("notificator") String notificator) throws MessageException, InterruptedException, StorageException { User user = permissionsService.getUser(getUserId()); - notificatorManager.getNotificator(notificator).send(user, new Event("test", 0), null); + notificatorManager.getNotificator(notificator).send(null, user, new Event("test", 0), null); return Response.noContent().build(); } diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index cb971b082..32216dfc6 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -107,8 +107,8 @@ public class NotificationManager { cacheManager.getNotificationUsers(notification.getId(), event.getDeviceId()).forEach(user -> { for (String notificator : notification.getNotificatorsTypes()) { try { - notificatorManager.getNotificator(notificator).send(user, event, position); - } catch (MessageException | InterruptedException exception) { + notificatorManager.getNotificator(notificator).send(notification, user, event, position); + } catch (MessageException exception) { LOGGER.warn("Notification failed", exception); } } diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java index 1d9f4f423..c3ee7b480 100644 --- a/src/main/java/org/traccar/notification/NotificatorManager.java +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,15 +17,13 @@ package org.traccar.notification; import com.google.inject.Injector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Typed; import org.traccar.notificators.Notificator; +import org.traccar.notificators.NotificatorCommand; import org.traccar.notificators.NotificatorFirebase; import org.traccar.notificators.NotificatorMail; -import org.traccar.notificators.NotificatorNull; import org.traccar.notificators.NotificatorPushover; import org.traccar.notificators.NotificatorSms; import org.traccar.notificators.NotificatorTelegram; @@ -43,9 +41,8 @@ import java.util.stream.Collectors; @Singleton public class NotificatorManager { - private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorManager.class); - private static final Map> NOTIFICATORS_ALL = Map.of( + "command", NotificatorCommand.class, "web", NotificatorWeb.class, "mail", NotificatorMail.class, "sms", NotificatorSms.class, @@ -75,8 +72,7 @@ public class NotificatorManager { return notificator; } } - LOGGER.warn("Failed to get notificator {}", type); - return new NotificatorNull(); + throw new RuntimeException("Failed to get notificator " + type); } public Set getAllNotificatorTypes() { diff --git a/src/main/java/org/traccar/notificators/Notificator.java b/src/main/java/org/traccar/notificators/Notificator.java index 052365c7a..cf71141c0 100644 --- a/src/main/java/org/traccar/notificators/Notificator.java +++ b/src/main/java/org/traccar/notificators/Notificator.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,12 +17,13 @@ package org.traccar.notificators; import org.traccar.model.Event; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; public interface Notificator { - void send(User user, Event event, Position position) throws MessageException, InterruptedException; + void send(Notification notification, User user, Event event, Position position) throws MessageException; } diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index 5ce2cbc0b..9fa2ebaf3 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,10 +26,10 @@ import com.google.firebase.messaging.Aps; import com.google.firebase.messaging.FirebaseMessaging; import com.google.firebase.messaging.FirebaseMessagingException; import com.google.firebase.messaging.MulticastMessage; -import com.google.firebase.messaging.Notification; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; @@ -64,7 +64,7 @@ public class NotificatorFirebase implements Notificator { } @Override - public void send(User user, Event event, Position position) throws MessageException { + public void send(Notification notification, User user, Event event, Position position) throws MessageException { if (user.hasAttribute("notificationTokens")) { var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); @@ -72,7 +72,7 @@ public class NotificatorFirebase implements Notificator { List registrationTokens = Arrays.asList(user.getString("notificationTokens").split("[, ]")); MulticastMessage message = MulticastMessage.builder() - .setNotification(Notification.builder() + .setNotification(com.google.firebase.messaging.Notification.builder() .setTitle(shortMessage.getSubject()) .setBody(shortMessage.getBody()) .build()) diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java index 19fde6756..7f755f170 100644 --- a/src/main/java/org/traccar/notificators/NotificatorMail.java +++ b/src/main/java/org/traccar/notificators/NotificatorMail.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,7 @@ package org.traccar.notificators; import org.traccar.mail.MailManager; import org.traccar.model.Event; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; @@ -40,7 +41,7 @@ public class NotificatorMail implements Notificator { } @Override - public void send(User user, Event event, Position position) throws MessageException { + public void send(Notification notification, User user, Event event, Position position) throws MessageException { try { var fullMessage = notificationFormatter.formatMessage(user, event, position, "full"); mailManager.sendMessage(user, fullMessage.getSubject(), fullMessage.getBody()); diff --git a/src/main/java/org/traccar/notificators/NotificatorNull.java b/src/main/java/org/traccar/notificators/NotificatorNull.java deleted file mode 100644 index ba9ade9c6..000000000 --- a/src/main/java/org/traccar/notificators/NotificatorNull.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@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.notificators; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.model.User; - -public class NotificatorNull implements Notificator { - - private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorNull.class); - - @Override - public void send(User user, Event event, Position position) { - LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent"); - } - -} diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index e00db0579..703d86876 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.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. @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; @@ -61,7 +62,7 @@ public class NotificatorPushover implements Notificator { } @Override - public void send(User user, Event event, Position position) { + public void send(Notification notification, User user, Event event, Position position) { var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); Message message = new Message(); diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java index e37d10888..7ec47b156 100644 --- a/src/main/java/org/traccar/notificators/NotificatorSms.java +++ b/src/main/java/org/traccar/notificators/NotificatorSms.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,7 @@ package org.traccar.notificators; import org.traccar.database.StatisticsManager; import org.traccar.model.Event; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; @@ -43,7 +44,7 @@ public class NotificatorSms implements Notificator { } @Override - public void send(User user, Event event, Position position) throws MessageException, InterruptedException { + public void send(Notification notification, User user, Event event, Position position) throws MessageException { if (user.getPhone() != null) { var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); statisticsManager.registerSms(); diff --git a/src/main/java/org/traccar/notificators/NotificatorTelegram.java b/src/main/java/org/traccar/notificators/NotificatorTelegram.java index 38e87c222..63d2bb717 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTelegram.java +++ b/src/main/java/org/traccar/notificators/NotificatorTelegram.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2021 Rafael Miquelino (rafaelmiquelino@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; @@ -85,7 +86,7 @@ public class NotificatorTelegram implements Notificator { } @Override - public void send(User user, Event event, Position position) { + public void send(Notification notification, User user, Event event, Position position) { var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); TextMessage message = new TextMessage(); diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index 9ae39f975..e32229506 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.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. @@ -37,7 +37,7 @@ public class NotificatorTraccar implements Notificator { private final String url; private final String key; - public static class Notification { + public static class NotificationObject { @JsonProperty("title") private String title; @JsonProperty("body") @@ -50,7 +50,7 @@ public class NotificatorTraccar implements Notificator { @JsonProperty("registration_ids") private String[] tokens; @JsonProperty("notification") - private Notification notification; + private NotificationObject notification; } @Inject @@ -62,19 +62,19 @@ public class NotificatorTraccar implements Notificator { } @Override - public void send(User user, Event event, Position position) { + public void send(org.traccar.model.Notification notification, User user, Event event, Position position) { if (user.hasAttribute("notificationTokens")) { var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); - Notification notification = new Notification(); - notification.title = shortMessage.getSubject(); - notification.body = shortMessage.getBody(); - notification.sound = "default"; + NotificationObject item = new NotificationObject(); + item.title = shortMessage.getSubject(); + item.body = shortMessage.getBody(); + item.sound = "default"; Message message = new Message(); message.tokens = user.getString("notificationTokens").split("[, ]"); - message.notification = notification; + message.notification = item; client.target(url).request().header("Authorization", "key=" + key).post(Entity.json(message)).close(); } diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java index deabeade1..51884074e 100644 --- a/src/main/java/org/traccar/notificators/NotificatorWeb.java +++ b/src/main/java/org/traccar/notificators/NotificatorWeb.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,6 +17,7 @@ package org.traccar.notificators; import org.traccar.model.Event; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; @@ -32,14 +33,13 @@ public final class NotificatorWeb implements Notificator { private final NotificationFormatter notificationFormatter; @Inject - public NotificatorWeb( - ConnectionManager connectionManager, NotificationFormatter notificationFormatter) { + public NotificatorWeb(ConnectionManager connectionManager, NotificationFormatter notificationFormatter) { this.connectionManager = connectionManager; this.notificationFormatter = notificationFormatter; } @Override - public void send(User user, Event event, Position position) { + public void send(Notification notification, User user, Event event, Position position) { Event copy = new Event(); copy.setId(event.getId()); diff --git a/src/main/java/org/traccar/sms/HttpSmsClient.java b/src/main/java/org/traccar/sms/HttpSmsClient.java index 51b161594..683022967 100644 --- a/src/main/java/org/traccar/sms/HttpSmsClient.java +++ b/src/main/java/org/traccar/sms/HttpSmsClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -67,7 +67,7 @@ public class HttpSmsClient implements SmsManager { } private String prepareValue(String value) throws UnsupportedEncodingException { - return encode ? URLEncoder.encode(value, StandardCharsets.UTF_8.name()) : value; + return encode ? URLEncoder.encode(value, StandardCharsets.UTF_8) : value; } private String preparePayload(String destAddress, String message) { diff --git a/src/main/java/org/traccar/sms/SmsManager.java b/src/main/java/org/traccar/sms/SmsManager.java index 9ab25d9cb..8cf99c9e8 100644 --- a/src/main/java/org/traccar/sms/SmsManager.java +++ b/src/main/java/org/traccar/sms/SmsManager.java @@ -20,7 +20,6 @@ import org.traccar.notification.MessageException; public interface SmsManager { - void sendMessage( - String destAddress, String message, boolean command) throws InterruptedException, MessageException; + void sendMessage(String destAddress, String message, boolean command) throws MessageException; } -- cgit v1.2.3 From cd1d80896b16c84ae0a8a4631a9dba6955e9e344 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Feb 2023 14:33:36 -0800 Subject: Implement command notificator --- schema/changelog-5.7.xml | 25 +++++++++ schema/changelog-master.xml | 1 + .../traccar/api/resource/NotificationResource.java | 6 +-- .../traccar/api/security/PermissionsService.java | 20 +++++-- src/main/java/org/traccar/model/Notification.java | 12 ++++- .../traccar/notificators/NotificatorCommand.java | 62 ++++++++++++++++++++++ 6 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 schema/changelog-5.7.xml create mode 100644 src/main/java/org/traccar/notificators/NotificatorCommand.java diff --git a/schema/changelog-5.7.xml b/schema/changelog-5.7.xml new file mode 100644 index 000000000..ad15ac48c --- /dev/null +++ b/schema/changelog-5.7.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index 0835918c9..1587cc789 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -37,5 +37,6 @@ + diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java index d58557601..7005fc083 100644 --- a/src/main/java/org/traccar/api/resource/NotificationResource.java +++ b/src/main/java/org/traccar/api/resource/NotificationResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -80,7 +80,7 @@ public class NotificationResource extends ExtendedObjectResource { @POST @Path("test") - public Response testMessage() throws MessageException, InterruptedException, StorageException { + public Response testMessage() throws MessageException, StorageException { User user = permissionsService.getUser(getUserId()); for (Typed method : notificatorManager.getAllNotificatorTypes()) { notificatorManager.getNotificator(method.getType()).send(null, user, new Event("test", 0), null); @@ -91,7 +91,7 @@ public class NotificationResource extends ExtendedObjectResource { @POST @Path("test/{notificator}") public Response testMessage(@PathParam("notificator") String notificator) - throws MessageException, InterruptedException, StorageException { + throws MessageException, StorageException { User user = permissionsService.getUser(getUserId()); notificatorManager.getNotificator(notificator).send(null, user, new Event("test", 0), null); return Response.noContent().build(); diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index 4421572d7..18a376601 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -23,6 +23,7 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.GroupedModel; import org.traccar.model.ManagedUser; +import org.traccar.model.Notification; import org.traccar.model.ScheduledModel; import org.traccar.model.Server; import org.traccar.model.User; @@ -129,7 +130,7 @@ public class PermissionsService { GroupedModel before = null; if (!addition) { before = storage.getObject(after.getClass(), new Request( - new Columns.Include("groupId"), new Condition.Equals("id", object.getId()))); + new Columns.Include("groupId"), new Condition.Equals("id", after.getId()))); } if (before == null || before.getGroupId() != after.getGroupId()) { checkPermission(Group.class, userId, after.getGroupId()); @@ -142,13 +143,26 @@ public class PermissionsService { ScheduledModel before = null; if (!addition) { before = storage.getObject(after.getClass(), new Request( - new Columns.Include("calendarId"), new Condition.Equals("id", object.getId()))); + new Columns.Include("calendarId"), new Condition.Equals("id", after.getId()))); } if (before == null || before.getCalendarId() != after.getCalendarId()) { checkPermission(Calendar.class, userId, after.getCalendarId()); } } } + if (object instanceof Notification) { + Notification after = ((Notification) object); + if (after.getCommandId() > 0) { + Notification before = null; + if (!addition) { + before = storage.getObject(after.getClass(), new Request( + new Columns.Include("commandId"), new Condition.Equals("id", after.getId()))); + } + if (before == null || before.getCommandId() != after.getCommandId()) { + checkPermission(Command.class, userId, after.getCommandId()); + } + } + } } } diff --git a/src/main/java/org/traccar/model/Notification.java b/src/main/java/org/traccar/model/Notification.java index 95e446132..b6a6e4cf5 100644 --- a/src/main/java/org/traccar/model/Notification.java +++ b/src/main/java/org/traccar/model/Notification.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -46,6 +46,16 @@ public class Notification extends ScheduledModel { this.type = type; } + private long commandId; + + public long getCommandId() { + return commandId; + } + + public void setCommandId(long commandId) { + this.commandId = commandId; + } + private String notificators; public String getNotificators() { diff --git a/src/main/java/org/traccar/notificators/NotificatorCommand.java b/src/main/java/org/traccar/notificators/NotificatorCommand.java new file mode 100644 index 000000000..55cbe0a6a --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorCommand.java @@ -0,0 +1,62 @@ +/* + * 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.notificators; + +import org.traccar.database.CommandsManager; +import org.traccar.model.Command; +import org.traccar.model.Event; +import org.traccar.model.Notification; +import org.traccar.model.Position; +import org.traccar.model.User; +import org.traccar.notification.MessageException; +import org.traccar.storage.Storage; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class NotificatorCommand implements Notificator { + + private final Storage storage; + private final CommandsManager commandsManager; + + @Inject + public NotificatorCommand(Storage storage, CommandsManager commandsManager) { + this.storage = storage; + this.commandsManager = commandsManager; + } + + @Override + public void send(Notification notification, User user, Event event, Position position) throws MessageException { + + if (notification == null || notification.getCommandId() <= 0) { + throw new MessageException("Saved command not provided"); + } + + try { + Command command = storage.getObject(Command.class, new Request( + new Columns.All(), new Condition.Equals("id", notification.getCommandId()))); + command.setDeviceId(event.getDeviceId()); + commandsManager.sendCommand(command); + } catch (Exception e) { + throw new MessageException(e); + } + } + +} -- cgit v1.2.3 From 754ff3a85baf2faaa1b962f16f52ebd0e12e6436 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Feb 2023 09:52:22 -0800 Subject: Add lock attribute --- src/main/java/org/traccar/model/Position.java | 1 + src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 1286db5f2..41cfeaf2e 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -83,6 +83,7 @@ public class Position extends Message { public static final String KEY_OPERATOR = "operator"; public static final String KEY_COMMAND = "command"; public static final String KEY_BLOCKED = "blocked"; + public static final String KEY_LOCK = "lock"; public static final String KEY_DOOR = "door"; public static final String KEY_AXLE_WEIGHT = "axleWeight"; public static final String KEY_G_SENSOR = "gSensor"; diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java index 313210f63..423ae3ffe 100644 --- a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java @@ -63,7 +63,7 @@ public class TeraTrackProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(json.getString("Speed")))); position.set(Position.KEY_ODOMETER, Integer.parseInt(json.getString("Mileage"))); - position.set(Position.KEY_BLOCKED, json.getString("LockOpen").equals("0")); + position.set(Position.KEY_LOCK, json.getString("LockOpen").equals("0")); position.set(Position.KEY_DRIVER_UNIQUE_ID, json.getString("CardNo")); position.set(Position.KEY_ALARM, json.getString("LowPower").equals("1") ? Position.ALARM_LOW_POWER : null); position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(json.getString("Power"))); -- cgit v1.2.3 From 392f00082faff72c9948ed569e4c883a5fabe7d6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Feb 2023 09:56:03 -0800 Subject: Support Meitrack K211G lock --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 6 ++++++ src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index a7accf0f1..5c5ba4be4 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -420,6 +420,12 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x15: position.set(Position.KEY_INPUT, buf.readUnsignedByte()); break; + case 0x47: + int lockState = buf.readUnsignedByte(); + if (lockState > 0) { + position.set(Position.KEY_LOCK, lockState == 2); + } + break; case 0x97: position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); break; diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 407d7a9b6..419eddf63 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "24245b3131342c3836343630363034343939333938372c4343452c0000000001005000130006012305000600070f1b004702060800000900000a00000b0000199d011a00000602d179570103b25ccc0604cf04862b0cc65b01000da4090d001c01000000010e0ccc010000b627be11000000002a41300d0a"), + Position.KEY_LOCK, true); + verifyAttribute(decoder, buffer( "$$u28,864606044993987,D82,0*D6"), Position.KEY_RESULT, "D82,0"); -- cgit v1.2.3 From 7678392d85f43c60c93f2a08dcba6aa7ec6102e4 Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Tue, 21 Feb 2023 22:39:14 +0300 Subject: Implement JEXL parser settings --- src/main/java/org/traccar/config/Keys.java | 95 ++++++++++++++++++++++ .../traccar/handler/ComputedAttributesHandler.java | 43 +++++++++- 2 files changed, 134 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 093f4298c..49af7cfab 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1299,6 +1299,101 @@ public final class Keys { public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey( "processing.computedAttributes.deviceAttributes", List.of(KeyType.CONFIG)); + /** + * Enable annotation constructs processing. + * When disabled, parsing a script/expression using syntactic annotation constructs (@annotation) will throw a parsing exception. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_ANNOTATION = new BooleanConfigKey( + "processing.computedAttributes.parser.annotation", + List.of(KeyType.CONFIG)); + /** + * Enable array references processing. + * When disabled, parsing a script/expression using 'obj[ ref ]' where ref is not a string or integer literal will throw a parsing exception; + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_ARRAY_REFERENCES = new BooleanConfigKey( + "processing.computedAttributes.parser.arrayReferences", + List.of(KeyType.CONFIG)); + /** + * Enable lambda declaration. + * When disabled, parsing a script/expression using syntactic lambda constructs (->,function) will throw a parsing exception. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LAMBDA = new BooleanConfigKey( + "processing.computedAttributes.parser.lambda", + List.of(KeyType.CONFIG)); + /** + * Enable whether redefining local variables is an error. + * When disabled, parsing a script/expression using a local variable or parameter syntax will throw a parsing exception. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL = new BooleanConfigKey( + "processing.computedAttributes.parser.lexical", + List.of(KeyType.CONFIG)); + /** + * Enable whether local variables shade global variables outside their scope. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL_SHADE = new BooleanConfigKey( + "processing.computedAttributes.parser.lexicalShade", + List.of(KeyType.CONFIG)); + /** + * Enable local variables declaration. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES = new BooleanConfigKey( + "processing.computedAttributes.parser.localVariables", + List.of(KeyType.CONFIG)); + /** + * Enable loops processing. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOOPS = new BooleanConfigKey( + "processing.computedAttributes.parser.loops", + List.of(KeyType.CONFIG)); + /** + * Set whether object method calls are enabled. + * When disabled, parsing a script/expression using 'obj.method()' will throw a parsing exception; + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_METHOD_CALLS = new BooleanConfigKey( + "processing.computedAttributes.parser.method_calls", + List.of(KeyType.CONFIG)); + /** + * Enable new instances creation. + * When disabled, parsing a script/expression using 'new(...)' will throw a parsing exception; using a class as functor will fail. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION = new BooleanConfigKey( + "processing.computedAttributes.parser.newInstanceCreation", + List.of(KeyType.CONFIG)); + /** + * Enable pragma expressions processing. + * When disabled, parsing a script/expression using syntactic pragma constructs (#pragma) will throw a parsing exception. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_PRAGMA = new BooleanConfigKey( + "processing.computedAttributes.parser.pragma", + List.of(KeyType.CONFIG)); + /** + * Enable scripts constructs processing. + * When disabled, parsing a script using syntactic script constructs (statements, ...) will throw a parsing exception. + * Dangerous, as can be used to escalate privileges on the Traccar server. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_SCRIPT_CONSTRUCTS = new BooleanConfigKey( + "processing.computedAttributes.parser.scriptConstructs", + List.of(KeyType.CONFIG)); + /** + * Enable side effect expressions processing. + * When disabled, parsing a script/expression using syntactical constructs modifying variables or members will throw a parsing exception. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT = new BooleanConfigKey( + "processing.computedAttributes.parser.sideEffect", + List.of(KeyType.CONFIG)); + /** + * Set whether side effect expressions on global variables (aka non-local) are enabled. + * When disabled, parsing a script/expression using syntactical constructs modifying variables including all potentially ant-ish variables will throw a parsing exception. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT_GLOBAL = new BooleanConfigKey( + "processing.computedAttributes.parser.sideEffectGlobal", + List.of(KeyType.CONFIG)); + /** + * Enable array/map/set literal expressions processing. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_STRUCTURED_LITERAL = new BooleanConfigKey( + "processing.computedAttributes.parser.structuredLiteral", + List.of(KeyType.CONFIG)); /** * Boolean flag to enable or disable reverse geocoder. diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index ca6c0fc74..c3f202fa2 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -26,10 +26,8 @@ import java.util.Map; import java.util.Set; import io.netty.channel.ChannelHandler; -import org.apache.commons.jexl3.JexlBuilder; -import org.apache.commons.jexl3.JexlEngine; -import org.apache.commons.jexl3.JexlException; -import org.apache.commons.jexl3.MapContext; +import org.apache.commons.jexl3.*; +import org.apache.commons.jexl3.introspection.JexlSandbox; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.BaseDataHandler; @@ -55,14 +53,51 @@ public class ComputedAttributesHandler extends BaseDataHandler { private final boolean includeDeviceAttributes; + @Inject public ComputedAttributesHandler(Config config, CacheManager cacheManager) { this.cacheManager = cacheManager; + boolean enableJEXLAnnotation = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_ANNOTATION); + boolean enableJEXLArrayReferences = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_ARRAY_REFERENCES); + boolean enableJEXLLambdas = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LAMBDA); + boolean enableJEXLLexical = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL); + boolean enableJEXLLexicalShade = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL_SHADE); + boolean enableJEXLLocalVariables = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES); + boolean enableJEXLLoops = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS); + boolean enableJEXLMethodCalls = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_METHOD_CALLS); + boolean enableJEXLNewInstanceCreation = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION); + boolean enableJEXLPragma = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_PRAGMA); + boolean enableJEXLScriptConstructs = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_SCRIPT_CONSTRUCTS); + boolean enableJEXLSideEffect = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT); + boolean enableJEXLSideEffectGlobal = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT_GLOBAL); + boolean enableJEXLStructuredLiteral = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_STRUCTURED_LITERAL); + JexlSandbox sandbox = new JexlSandbox(false); + sandbox.allow("com.safe.Functions"); + boolean enableJEXLRegister = true; + JexlFeatures features = new JexlFeatures() + .annotation(enableJEXLAnnotation) + .arrayReferenceExpr(enableJEXLArrayReferences) + .lambda(enableJEXLLambdas) + .lexical(enableJEXLLexical) + .lexicalShade(enableJEXLLexicalShade) + .localVar(enableJEXLLocalVariables) + .loops(enableJEXLLoops) + .methodCall(enableJEXLMethodCalls) + .newInstance(enableJEXLNewInstanceCreation) + .pragma(enableJEXLPragma) + .register(enableJEXLRegister) + .script(enableJEXLScriptConstructs) + .sideEffect(enableJEXLSideEffect) + .sideEffectGlobal(enableJEXLSideEffectGlobal) + .structuredLiteral(enableJEXLStructuredLiteral); engine = new JexlBuilder() .strict(true) .namespaces(Collections.singletonMap("math", Math.class)) + .sandbox(sandbox) + .features(features) .create(); includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); + } private MapContext prepareContext(Position position) { -- cgit v1.2.3 From a41ad7237035b27634cd6eac1a68e3cf1b553be9 Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Tue, 21 Feb 2023 23:14:35 +0300 Subject: Shorten JEXL features palette --- src/main/java/org/traccar/config/Keys.java | 83 +--------------------- .../traccar/handler/ComputedAttributesHandler.java | 25 +------ 2 files changed, 4 insertions(+), 104 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 49af7cfab..53f0336cc 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1299,102 +1299,25 @@ public final class Keys { public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey( "processing.computedAttributes.deviceAttributes", List.of(KeyType.CONFIG)); - /** - * Enable annotation constructs processing. - * When disabled, parsing a script/expression using syntactic annotation constructs (@annotation) will throw a parsing exception. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_ANNOTATION = new BooleanConfigKey( - "processing.computedAttributes.parser.annotation", - List.of(KeyType.CONFIG)); - /** - * Enable array references processing. - * When disabled, parsing a script/expression using 'obj[ ref ]' where ref is not a string or integer literal will throw a parsing exception; - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_ARRAY_REFERENCES = new BooleanConfigKey( - "processing.computedAttributes.parser.arrayReferences", - List.of(KeyType.CONFIG)); - /** - * Enable lambda declaration. - * When disabled, parsing a script/expression using syntactic lambda constructs (->,function) will throw a parsing exception. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LAMBDA = new BooleanConfigKey( - "processing.computedAttributes.parser.lambda", - List.of(KeyType.CONFIG)); - /** - * Enable whether redefining local variables is an error. - * When disabled, parsing a script/expression using a local variable or parameter syntax will throw a parsing exception. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL = new BooleanConfigKey( - "processing.computedAttributes.parser.lexical", - List.of(KeyType.CONFIG)); - /** - * Enable whether local variables shade global variables outside their scope. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL_SHADE = new BooleanConfigKey( - "processing.computedAttributes.parser.lexicalShade", - List.of(KeyType.CONFIG)); /** * Enable local variables declaration. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES = new BooleanConfigKey( - "processing.computedAttributes.parser.localVariables", + "processing.computedAttributes.localVariables", List.of(KeyType.CONFIG)); /** * Enable loops processing. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOOPS = new BooleanConfigKey( - "processing.computedAttributes.parser.loops", - List.of(KeyType.CONFIG)); - /** - * Set whether object method calls are enabled. - * When disabled, parsing a script/expression using 'obj.method()' will throw a parsing exception; - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_METHOD_CALLS = new BooleanConfigKey( - "processing.computedAttributes.parser.method_calls", + "processing.computedAttributes.loops", List.of(KeyType.CONFIG)); /** * Enable new instances creation. * When disabled, parsing a script/expression using 'new(...)' will throw a parsing exception; using a class as functor will fail. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION = new BooleanConfigKey( - "processing.computedAttributes.parser.newInstanceCreation", + "processing.computedAttributes.newInstanceCreation", List.of(KeyType.CONFIG)); - /** - * Enable pragma expressions processing. - * When disabled, parsing a script/expression using syntactic pragma constructs (#pragma) will throw a parsing exception. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_PRAGMA = new BooleanConfigKey( - "processing.computedAttributes.parser.pragma", - List.of(KeyType.CONFIG)); - /** - * Enable scripts constructs processing. - * When disabled, parsing a script using syntactic script constructs (statements, ...) will throw a parsing exception. - * Dangerous, as can be used to escalate privileges on the Traccar server. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_SCRIPT_CONSTRUCTS = new BooleanConfigKey( - "processing.computedAttributes.parser.scriptConstructs", - List.of(KeyType.CONFIG)); - /** - * Enable side effect expressions processing. - * When disabled, parsing a script/expression using syntactical constructs modifying variables or members will throw a parsing exception. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT = new BooleanConfigKey( - "processing.computedAttributes.parser.sideEffect", - List.of(KeyType.CONFIG)); - /** - * Set whether side effect expressions on global variables (aka non-local) are enabled. - * When disabled, parsing a script/expression using syntactical constructs modifying variables including all potentially ant-ish variables will throw a parsing exception. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT_GLOBAL = new BooleanConfigKey( - "processing.computedAttributes.parser.sideEffectGlobal", - List.of(KeyType.CONFIG)); - /** - * Enable array/map/set literal expressions processing. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_STRUCTURED_LITERAL = new BooleanConfigKey( - "processing.computedAttributes.parser.structuredLiteral", - List.of(KeyType.CONFIG)); - /** * Boolean flag to enable or disable reverse geocoder. */ diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index c3f202fa2..912665630 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -57,39 +57,16 @@ public class ComputedAttributesHandler extends BaseDataHandler { @Inject public ComputedAttributesHandler(Config config, CacheManager cacheManager) { this.cacheManager = cacheManager; - boolean enableJEXLAnnotation = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_ANNOTATION); - boolean enableJEXLArrayReferences = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_ARRAY_REFERENCES); - boolean enableJEXLLambdas = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LAMBDA); - boolean enableJEXLLexical = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL); - boolean enableJEXLLexicalShade = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LEXICAL_SHADE); boolean enableJEXLLocalVariables = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES); boolean enableJEXLLoops = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS); - boolean enableJEXLMethodCalls = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_METHOD_CALLS); boolean enableJEXLNewInstanceCreation = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION); - boolean enableJEXLPragma = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_PRAGMA); - boolean enableJEXLScriptConstructs = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_SCRIPT_CONSTRUCTS); - boolean enableJEXLSideEffect = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT); - boolean enableJEXLSideEffectGlobal = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_SIDE_EFFECT_GLOBAL); - boolean enableJEXLStructuredLiteral = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_STRUCTURED_LITERAL); JexlSandbox sandbox = new JexlSandbox(false); sandbox.allow("com.safe.Functions"); - boolean enableJEXLRegister = true; JexlFeatures features = new JexlFeatures() - .annotation(enableJEXLAnnotation) - .arrayReferenceExpr(enableJEXLArrayReferences) - .lambda(enableJEXLLambdas) - .lexical(enableJEXLLexical) - .lexicalShade(enableJEXLLexicalShade) .localVar(enableJEXLLocalVariables) .loops(enableJEXLLoops) - .methodCall(enableJEXLMethodCalls) .newInstance(enableJEXLNewInstanceCreation) - .pragma(enableJEXLPragma) - .register(enableJEXLRegister) - .script(enableJEXLScriptConstructs) - .sideEffect(enableJEXLSideEffect) - .sideEffectGlobal(enableJEXLSideEffectGlobal) - .structuredLiteral(enableJEXLStructuredLiteral); + .structuredLiteral(true); engine = new JexlBuilder() .strict(true) .namespaces(Collections.singletonMap("math", Math.class)) -- cgit v1.2.3 From 99bbdac84d85ec57c9f7955ba353c86217e0dabc Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Tue, 21 Feb 2023 23:38:13 +0300 Subject: fix imports --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 912665630..76f9c8f24 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -26,8 +26,12 @@ import java.util.Map; import java.util.Set; import io.netty.channel.ChannelHandler; -import org.apache.commons.jexl3.*; +import org.apache.commons.jexl3.JexlFeatures; +import org.apache.commons.jexl3.JexlEngine; +import org.apache.commons.jexl3.JexlBuilder; import org.apache.commons.jexl3.introspection.JexlSandbox; +import org.apache.commons.jexl3.JexlException; +import org.apache.commons.jexl3.MapContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.BaseDataHandler; -- cgit v1.2.3 From 5bed640e8b87526a077d6a8411cddfac9c8661ae Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Wed, 22 Feb 2023 07:20:49 +0300 Subject: note comments --- .../java/org/traccar/handler/ComputedAttributesHandler.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 76f9c8f24..73b549195 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -57,19 +57,15 @@ public class ComputedAttributesHandler extends BaseDataHandler { private final boolean includeDeviceAttributes; - @Inject public ComputedAttributesHandler(Config config, CacheManager cacheManager) { this.cacheManager = cacheManager; - boolean enableJEXLLocalVariables = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES); - boolean enableJEXLLoops = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS); - boolean enableJEXLNewInstanceCreation = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION); JexlSandbox sandbox = new JexlSandbox(false); sandbox.allow("com.safe.Functions"); JexlFeatures features = new JexlFeatures() - .localVar(enableJEXLLocalVariables) - .loops(enableJEXLLoops) - .newInstance(enableJEXLNewInstanceCreation) + .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) + .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS)) + .newInstance(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION)) .structuredLiteral(true); engine = new JexlBuilder() .strict(true) @@ -78,7 +74,6 @@ public class ComputedAttributesHandler extends BaseDataHandler { .features(features) .create(); includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); - } private MapContext prepareContext(Position position) { -- cgit v1.2.3 From 51f0299aefe728163ac69f36cf9223c08ecd97aa Mon Sep 17 00:00:00 2001 From: Alexandre Truppel Date: Wed, 22 Feb 2023 14:27:07 +0100 Subject: Start writing boolean special case --- .../traccar/protocol/WialonProtocolDecoder.java | 60 ++++++++++++++-------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index b87ba2b53..1fc434ed8 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -39,31 +39,31 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN_ANY = new PatternBuilder() - .expression("([^#]+)?") // imei - .text("#") // start byte - .expression("([^#]+)") // type - .text("#") // separator - .expression("(.*)") // message + .expression("([^#]+)?") // imei + .text("#") // start byte + .expression("([^#]+)") // type + .text("#") // separator + .expression("(.*)") // message .compile(); private static final Pattern PATTERN = new PatternBuilder() - .number("(?:NA|(dd)(dd)(dd));") // date (ddmmyy) - .number("(?:NA|(dd)(dd)(dd));") // time (hhmmss) - .number("(?:NA|(dd)(dd.d+));") // latitude + .number("(?:NA|(dd)(dd)(dd));") // date (ddmmyy) + .number("(?:NA|(dd)(dd)(dd));") // time (hhmmss) + .number("(?:NA|(dd)(dd.d+));") // latitude .expression("(?:NA|([NS]));") - .number("(?:NA|(ddd)(dd.d+));") // longitude + .number("(?:NA|(ddd)(dd.d+));") // longitude .expression("(?:NA|([EW]));") - .number("(?:NA|(d+.?d*))?;") // speed - .number("(?:NA|(d+.?d*))?;") // course - .number("(?:NA|(-?d+.?d*));") // altitude - .number("(?:NA|(d+))") // satellites + .number("(?:NA|(d+.?d*))?;") // speed + .number("(?:NA|(d+.?d*))?;") // course + .number("(?:NA|(-?d+.?d*));") // altitude + .number("(?:NA|(d+))") // satellites .groupBegin().text(";") - .number("(?:NA|(d+.?d*));") // hdop - .number("(?:NA|(d+));") // inputs - .number("(?:NA|(d+));") // outputs - .expression("(?:NA|([^;]*));") // adc - .expression("(?:NA|([^;]*));") // ibutton - .expression("(?:NA|(.*))") // params + .number("(?:NA|(d+.?d*));") // hdop + .number("(?:NA|(d+));") // inputs + .number("(?:NA|(d+));") // outputs + .expression("(?:NA|([^;]*));") // adc + .expression("(?:NA|([^;]*));") // ibutton + .expression("(?:NA|(.*))") // params .groupEnd("?") .compile(); @@ -135,10 +135,28 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { for (String param : values) { Matcher paramParser = Pattern.compile("(.*):[1-3]:(.*)").matcher(param); if (paramParser.matches()) { + // Parsing gives a (string,string) key-value pair + String key = paramParser.group(1).toLowerCase(); + String value = paramParser.group(2); + + // Key is already in correct type (string) + // If we can parse the value as a double, then we use that as the value's type + // If not, value type is a string unless it is equal to some specific cases (true, yes, etc), in which case we convert into a boolean + try { - position.set(paramParser.group(1).toLowerCase(), Double.parseDouble(paramParser.group(2))); + position.set(key, Double.parseDouble(value)); } catch (NumberFormatException e) { - position.set(paramParser.group(1).toLowerCase(), paramParser.group(2)); + if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("t") + || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("y") + || value.equalsIgnoreCase("on")) { + position.set(key, true); + } else if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("f") + || value.equalsIgnoreCase("no") || value.equalsIgnoreCase("n") + || value.equalsIgnoreCase("off")) { + position.set(key, false); + } else { + position.set(key, value); + } } } } -- cgit v1.2.3 From 345262a970292541c07aee9982c6a26a29c11f9c Mon Sep 17 00:00:00 2001 From: Alexandre Truppel Date: Wed, 22 Feb 2023 15:36:45 +0100 Subject: Boolean special case for Wialon done, added tests --- src/main/java/org/traccar/protocol/WialonProtocolDecoder.java | 10 +++++++--- .../java/org/traccar/protocol/WialonProtocolDecoderTest.java | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index 1fc434ed8..4c4ff7a63 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -140,9 +140,13 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { String value = paramParser.group(2); // Key is already in correct type (string) - // If we can parse the value as a double, then we use that as the value's type - // If not, value type is a string unless it is equal to some specific cases (true, yes, etc), in which case we convert into a boolean - + + // If we can parse the value as a double, then we use that as the value's type. + // This covers both integer (x:1:y) and double (x:2:y) types in the Wialon protocol + + // If not, value type is a string unless it is equal to some specific cases + // (true, yes, etc), in which case we convert into a boolean + try { position.set(key, Double.parseDouble(value)); } catch (NumberFormatException e) { diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java index 6953784fb..45fbfbb1d 100644 --- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java @@ -19,6 +19,12 @@ public class WialonProtocolDecoderTest extends ProtocolTest { verifyAttributes(decoder, text( "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;101_521347:1:521246,101_158:1:510,101_521055:1:510,101_521055_2.9:1:509,101_521056:1:3;626B")); + verifyAttributes(decoder, text( + "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:true")); + + verifyAttributes(decoder, text( + "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false")); + verifyNull(decoder, text( "#L#123456789012345;test")); -- cgit v1.2.3 From ba6a9d72e62282d64781b856b8e094e1fb612f9e Mon Sep 17 00:00:00 2001 From: Alexandre Truppel Date: Wed, 22 Feb 2023 15:50:19 +0100 Subject: Added "setAccuracy" special case, with tests --- .../org/traccar/protocol/WialonProtocolDecoder.java | 11 ++++++++++- .../traccar/protocol/WialonProtocolDecoderTest.java | 18 ++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index 4c4ff7a63..e2ccfe9d8 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -148,7 +148,16 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { // (true, yes, etc), in which case we convert into a boolean try { - position.set(key, Double.parseDouble(value)); + double double_value = Double.parseDouble(value); + + // Since accuracy is not part of the general parameter list, + // we need to handle it separately by calling setAccuracy directly + if (key.equals("accuracy")) { + position.setAccuracy(double_value); + } + else { + position.set(key, double_value); + } } catch (NumberFormatException e) { if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("t") || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("y") diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java index 45fbfbb1d..e25ff7f9e 100644 --- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java @@ -1,8 +1,11 @@ package org.traccar.protocol; +import org.traccar.model.Position; import org.junit.Test; import org.traccar.ProtocolTest; +import static org.junit.Assert.assertEquals; + public class WialonProtocolDecoderTest extends ProtocolTest { @Test @@ -19,12 +22,6 @@ public class WialonProtocolDecoderTest extends ProtocolTest { verifyAttributes(decoder, text( "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;101_521347:1:521246,101_158:1:510,101_521055:1:510,101_521055_2.9:1:509,101_521056:1:3;626B")); - verifyAttributes(decoder, text( - "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:true")); - - verifyAttributes(decoder, text( - "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false")); - verifyNull(decoder, text( "#L#123456789012345;test")); @@ -81,6 +78,15 @@ public class WialonProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, text( "#B#110315;045857;5364.0167;N;06127.8262;E;0;155;965;7;2.40;4;0;14.77,0.02,3.6;AB45DF01145;")); + verifyAttributes(decoder, text( + "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:true")); + + verifyAttributes(decoder, text( + "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false")); + + Position p = (Position)decoder.decode(null, null, text( + "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;accuracy:2:12.3")); + assertEquals(p.getAccuracy(), 12.3, 0.001); } } -- cgit v1.2.3 From 6c4f99117bbd3645f3b55852b2148beb28c1e0f9 Mon Sep 17 00:00:00 2001 From: Alexandre Truppel Date: Wed, 22 Feb 2023 15:58:43 +0100 Subject: Corrected styling --- src/main/java/org/traccar/protocol/WialonProtocolDecoder.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index e2ccfe9d8..baf3847a1 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -148,15 +148,14 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { // (true, yes, etc), in which case we convert into a boolean try { - double double_value = Double.parseDouble(value); + double doubleValue = Double.parseDouble(value); // Since accuracy is not part of the general parameter list, // we need to handle it separately by calling setAccuracy directly if (key.equals("accuracy")) { - position.setAccuracy(double_value); - } - else { - position.set(key, double_value); + position.setAccuracy(doubleValue); + } else { + position.set(key, doubleValue); } } catch (NumberFormatException e) { if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("t") -- cgit v1.2.3 From 47398e91b1450c744cf3ed31de46f7ea02bbede1 Mon Sep 17 00:00:00 2001 From: Alexandre Truppel Date: Wed, 22 Feb 2023 16:05:21 +0100 Subject: Review --- src/main/java/org/traccar/protocol/WialonProtocolDecoder.java | 10 +++------- .../java/org/traccar/protocol/WialonProtocolDecoderTest.java | 11 ++--------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index baf3847a1..1166d0708 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -145,7 +145,7 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { // This covers both integer (x:1:y) and double (x:2:y) types in the Wialon protocol // If not, value type is a string unless it is equal to some specific cases - // (true, yes, etc), in which case we convert into a boolean + // (true, false), in which case we convert into a boolean try { double doubleValue = Double.parseDouble(value); @@ -158,13 +158,9 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { position.set(key, doubleValue); } } catch (NumberFormatException e) { - if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("t") - || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("y") - || value.equalsIgnoreCase("on")) { + if (value.equalsIgnoreCase("true")) { position.set(key, true); - } else if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("f") - || value.equalsIgnoreCase("no") || value.equalsIgnoreCase("n") - || value.equalsIgnoreCase("off")) { + } else if (value.equalsIgnoreCase("false")) { position.set(key, false); } else { position.set(key, value); diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java index e25ff7f9e..0a47edcb4 100644 --- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java @@ -78,15 +78,8 @@ public class WialonProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, text( "#B#110315;045857;5364.0167;N;06127.8262;E;0;155;965;7;2.40;4;0;14.77,0.02,3.6;AB45DF01145;")); - verifyAttributes(decoder, text( - "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:true")); - - verifyAttributes(decoder, text( - "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false")); - - Position p = (Position)decoder.decode(null, null, text( - "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;accuracy:2:12.3")); - assertEquals(p.getAccuracy(), 12.3, 0.001); + verifyAttribute(decoder, text( + "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false"), "motion", false); } } -- cgit v1.2.3 From a2d9daf4b21313ebaed862f126355becf2b6d4ec Mon Sep 17 00:00:00 2001 From: Alexandre Truppel Date: Wed, 22 Feb 2023 16:07:05 +0100 Subject: Formatting --- .../traccar/protocol/WialonProtocolDecoder.java | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index 1166d0708..b319a5947 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -39,31 +39,31 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN_ANY = new PatternBuilder() - .expression("([^#]+)?") // imei - .text("#") // start byte - .expression("([^#]+)") // type - .text("#") // separator - .expression("(.*)") // message + .expression("([^#]+)?") // imei + .text("#") // start byte + .expression("([^#]+)") // type + .text("#") // separator + .expression("(.*)") // message .compile(); private static final Pattern PATTERN = new PatternBuilder() - .number("(?:NA|(dd)(dd)(dd));") // date (ddmmyy) - .number("(?:NA|(dd)(dd)(dd));") // time (hhmmss) - .number("(?:NA|(dd)(dd.d+));") // latitude + .number("(?:NA|(dd)(dd)(dd));") // date (ddmmyy) + .number("(?:NA|(dd)(dd)(dd));") // time (hhmmss) + .number("(?:NA|(dd)(dd.d+));") // latitude .expression("(?:NA|([NS]));") - .number("(?:NA|(ddd)(dd.d+));") // longitude + .number("(?:NA|(ddd)(dd.d+));") // longitude .expression("(?:NA|([EW]));") - .number("(?:NA|(d+.?d*))?;") // speed - .number("(?:NA|(d+.?d*))?;") // course - .number("(?:NA|(-?d+.?d*));") // altitude - .number("(?:NA|(d+))") // satellites + .number("(?:NA|(d+.?d*))?;") // speed + .number("(?:NA|(d+.?d*))?;") // course + .number("(?:NA|(-?d+.?d*));") // altitude + .number("(?:NA|(d+))") // satellites .groupBegin().text(";") - .number("(?:NA|(d+.?d*));") // hdop - .number("(?:NA|(d+));") // inputs - .number("(?:NA|(d+));") // outputs - .expression("(?:NA|([^;]*));") // adc - .expression("(?:NA|([^;]*));") // ibutton - .expression("(?:NA|(.*))") // params + .number("(?:NA|(d+.?d*));") // hdop + .number("(?:NA|(d+));") // inputs + .number("(?:NA|(d+));") // outputs + .expression("(?:NA|([^;]*));") // adc + .expression("(?:NA|([^;]*));") // ibutton + .expression("(?:NA|(.*))") // params .groupEnd("?") .compile(); -- cgit v1.2.3 From 2b7c3ecde2512478dac381feaab9d35a93c3b9cb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Feb 2023 07:15:04 -0800 Subject: Small code cleanup --- .../org/traccar/protocol/WialonProtocolDecoder.java | 18 ++---------------- .../traccar/protocol/WialonProtocolDecoderTest.java | 6 ++---- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index b319a5947..ffa4472ef 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -135,27 +135,13 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { for (String param : values) { Matcher paramParser = Pattern.compile("(.*):[1-3]:(.*)").matcher(param); if (paramParser.matches()) { - // Parsing gives a (string,string) key-value pair String key = paramParser.group(1).toLowerCase(); String value = paramParser.group(2); - - // Key is already in correct type (string) - - // If we can parse the value as a double, then we use that as the value's type. - // This covers both integer (x:1:y) and double (x:2:y) types in the Wialon protocol - - // If not, value type is a string unless it is equal to some specific cases - // (true, false), in which case we convert into a boolean - try { - double doubleValue = Double.parseDouble(value); - - // Since accuracy is not part of the general parameter list, - // we need to handle it separately by calling setAccuracy directly if (key.equals("accuracy")) { - position.setAccuracy(doubleValue); + position.setAccuracy(Double.parseDouble(value)); } else { - position.set(key, doubleValue); + position.set(key, Double.parseDouble(value)); } } catch (NumberFormatException e) { if (value.equalsIgnoreCase("true")) { diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java index 0a47edcb4..29a86e0ac 100644 --- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java @@ -1,11 +1,8 @@ package org.traccar.protocol; -import org.traccar.model.Position; import org.junit.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; - public class WialonProtocolDecoderTest extends ProtocolTest { @Test @@ -79,7 +76,8 @@ public class WialonProtocolDecoderTest extends ProtocolTest { "#B#110315;045857;5364.0167;N;06127.8262;E;0;155;965;7;2.40;4;0;14.77,0.02,3.6;AB45DF01145;")); verifyAttribute(decoder, text( - "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false"), "motion", false); + "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false"), + "motion", false); } } -- cgit v1.2.3 From 9deca13ced10ef8a6df164831dd60ed4089a25a6 Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Wed, 22 Feb 2023 21:43:47 +0300 Subject: lint patch --- src/main/java/org/traccar/config/Keys.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 53f0336cc..6aa41f85b 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1299,25 +1299,29 @@ public final class Keys { public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey( "processing.computedAttributes.deviceAttributes", List.of(KeyType.CONFIG)); + /** * Enable local variables declaration. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES = new BooleanConfigKey( "processing.computedAttributes.localVariables", List.of(KeyType.CONFIG)); + /** * Enable loops processing. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOOPS = new BooleanConfigKey( "processing.computedAttributes.loops", List.of(KeyType.CONFIG)); + /** * Enable new instances creation. - * When disabled, parsing a script/expression using 'new(...)' will throw a parsing exception; using a class as functor will fail. + * When disabled, parsing a script/expression using 'new(...)' will throw a parsing exception; */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION = new BooleanConfigKey( "processing.computedAttributes.newInstanceCreation", List.of(KeyType.CONFIG)); + /** * Boolean flag to enable or disable reverse geocoder. */ -- cgit v1.2.3 From 0fe0344a64b142ef4492ff6ad3c1f8590d336ab0 Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Wed, 22 Feb 2023 22:46:50 +0300 Subject: Alternative features activation way --- src/main/java/org/traccar/config/Keys.java | 8 ++++---- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6aa41f85b..d3bba9ae7 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1299,21 +1299,21 @@ public final class Keys { public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey( "processing.computedAttributes.deviceAttributes", List.of(KeyType.CONFIG)); - + /** * Enable local variables declaration. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES = new BooleanConfigKey( "processing.computedAttributes.localVariables", List.of(KeyType.CONFIG)); - + /** * Enable loops processing. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOOPS = new BooleanConfigKey( "processing.computedAttributes.loops", List.of(KeyType.CONFIG)); - + /** * Enable new instances creation. * When disabled, parsing a script/expression using 'new(...)' will throw a parsing exception; @@ -1321,7 +1321,7 @@ public final class Keys { public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION = new BooleanConfigKey( "processing.computedAttributes.newInstanceCreation", List.of(KeyType.CONFIG)); - + /** * Boolean flag to enable or disable reverse geocoder. */ diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 73b549195..2964d81d7 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -55,6 +55,8 @@ public class ComputedAttributesHandler extends BaseDataHandler { private final JexlEngine engine; + private final JexlFeatures features; + private final boolean includeDeviceAttributes; @Inject @@ -62,7 +64,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { this.cacheManager = cacheManager; JexlSandbox sandbox = new JexlSandbox(false); sandbox.allow("com.safe.Functions"); - JexlFeatures features = new JexlFeatures() + features = new JexlFeatures() .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS)) .newInstance(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION)) @@ -71,7 +73,6 @@ public class ComputedAttributesHandler extends BaseDataHandler { .strict(true) .namespaces(Collections.singletonMap("math", Math.class)) .sandbox(sandbox) - .features(features) .create(); includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); } @@ -113,7 +114,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { */ @Deprecated public Object computeAttribute(Attribute attribute, Position position) throws JexlException { - return engine.createExpression(attribute.getExpression()).evaluate(prepareContext(position)); + return engine.createScript(features, engine.createInfo(), attribute.getExpression()).execute(prepareContext(position)); } @Override -- cgit v1.2.3 From 41fe87006c89ee1ddf727878448ba83cb4537ebf Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Wed, 22 Feb 2023 23:11:25 +0300 Subject: Fix Math namespace --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 2964d81d7..0eab509ee 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -64,6 +64,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { this.cacheManager = cacheManager; JexlSandbox sandbox = new JexlSandbox(false); sandbox.allow("com.safe.Functions"); + sandbox.allow(Math.class.getName()); features = new JexlFeatures() .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS)) -- cgit v1.2.3 From 7a8fc065a116af1f944959354495db00459d2199 Mon Sep 17 00:00:00 2001 From: memesaregood1 Date: Thu, 23 Feb 2023 22:07:42 +0300 Subject: Fix lint issues once again --- src/main/java/org/traccar/config/Keys.java | 8 ++++---- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index d3bba9ae7..6aa41f85b 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1299,21 +1299,21 @@ public final class Keys { public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey( "processing.computedAttributes.deviceAttributes", List.of(KeyType.CONFIG)); - + /** * Enable local variables declaration. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES = new BooleanConfigKey( "processing.computedAttributes.localVariables", List.of(KeyType.CONFIG)); - + /** * Enable loops processing. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LOOPS = new BooleanConfigKey( "processing.computedAttributes.loops", List.of(KeyType.CONFIG)); - + /** * Enable new instances creation. * When disabled, parsing a script/expression using 'new(...)' will throw a parsing exception; @@ -1321,7 +1321,7 @@ public final class Keys { public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION = new BooleanConfigKey( "processing.computedAttributes.newInstanceCreation", List.of(KeyType.CONFIG)); - + /** * Boolean flag to enable or disable reverse geocoder. */ diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 0eab509ee..e8a4998e3 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -115,7 +115,9 @@ public class ComputedAttributesHandler extends BaseDataHandler { */ @Deprecated public Object computeAttribute(Attribute attribute, Position position) throws JexlException { - return engine.createScript(features, engine.createInfo(), attribute.getExpression()).execute(prepareContext(position)); + return engine.createScript(features, + engine.createInfo(), + attribute.getExpression()).execute(prepareContext(position)); } @Override -- cgit v1.2.3 From 1da3bc7bfe9bcd6a7a6fe9105973e93772657597 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Feb 2023 11:19:26 -0800 Subject: Minor formatting change --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index e8a4998e3..7671fcc2f 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -115,9 +115,8 @@ public class ComputedAttributesHandler extends BaseDataHandler { */ @Deprecated public Object computeAttribute(Attribute attribute, Position position) throws JexlException { - return engine.createScript(features, - engine.createInfo(), - attribute.getExpression()).execute(prepareContext(position)); + return engine.createScript(features,engine.createInfo(), attribute.getExpression()) + .execute(prepareContext(position)); } @Override -- cgit v1.2.3 From b943cdbc7bce5d28e9c32b16b17bf3da6380e031 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Feb 2023 11:22:36 -0800 Subject: Minor formatting change --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 7671fcc2f..d384bbffc 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -115,7 +115,8 @@ public class ComputedAttributesHandler extends BaseDataHandler { */ @Deprecated public Object computeAttribute(Attribute attribute, Position position) throws JexlException { - return engine.createScript(features,engine.createInfo(), attribute.getExpression()) + return engine + .createScript(features, engine.createInfo(), attribute.getExpression()) .execute(prepareContext(position)); } -- cgit v1.2.3 From 2ac77554f7771a014d62a6e5eeb381b4650dc4f4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Feb 2023 16:20:23 -0800 Subject: Fix short trips and stops --- .../org/traccar/reports/common/ReportUtils.java | 2 +- .../java/org/traccar/reports/ReportUtilsTest.java | 34 +++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index a7c420095..35faa9c8b 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -386,7 +386,7 @@ public class ReportUtils { } } } - if (startEventIndex >= 0 && startEventIndex < positions.size() - 1) { + if (detected & startEventIndex >= 0 && startEventIndex < positions.size() - 1) { int endIndex = startNoEventIndex >= 0 ? startNoEventIndex : positions.size() - 1; result.add(calculateTripOrStop( device, positions, startEventIndex, endIndex, ignoreOdometer, reportClass)); diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index 4bf668064..aa166dc25 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -98,8 +98,8 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:03:00.000", 10, 1000), position("2016-01-01 00:04:00.000", 10, 2000), position("2016-01-01 00:05:00.000", 0, 3000), - position("2016-01-01 00:06:00.000", 0, 3000), - position("2016-01-01 00:07:00.000", 0, 3000)); + position("2016-01-01 00:15:00.000", 0, 3000), + position("2016-01-01 00:25:00.000", 0, 3000)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); ReportUtils reportUtils = new ReportUtils( @@ -136,8 +136,8 @@ public class ReportUtilsTest extends BaseTest { itemStop = iterator.next(); assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getStartTime()); - assertEquals(date("2016-01-01 00:07:00.000"), itemStop.getEndTime()); - assertEquals(120000, itemStop.getDuration()); + assertEquals(date("2016-01-01 00:25:00.000"), itemStop.getEndTime()); + assertEquals(1200000, itemStop.getDuration()); } @@ -151,8 +151,8 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:03:00.000", 10, 1000), position("2016-01-01 00:04:00.000", 10, 2000), position("2016-01-01 00:05:00.000", 0, 3000), - position("2016-01-01 00:06:00.000", 0, 3000), - position("2016-01-01 00:07:00.000", 0, 3000)); + position("2016-01-01 00:15:00.000", 0, 3000), + position("2016-01-01 00:25:00.000", 0, 3000)); data.get(5).set(Position.KEY_IGNITION, false); @@ -205,8 +205,8 @@ public class ReportUtilsTest extends BaseTest { itemStop = iterator.next(); assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getStartTime()); - assertEquals(date("2016-01-01 00:07:00.000"), itemStop.getEndTime()); - assertEquals(120000, itemStop.getDuration()); + assertEquals(date("2016-01-01 00:25:00.000"), itemStop.getEndTime()); + assertEquals(1200000, itemStop.getDuration()); } @@ -224,8 +224,8 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:07:00.000", 0, 5000), position("2016-01-01 00:08:00.000", 10, 6000), position("2016-01-01 00:09:00.000", 0, 7000), - position("2016-01-01 00:10:00.000", 0, 7000), - position("2016-01-01 00:11:00.000", 0, 7000)); + position("2016-01-01 00:19:00.000", 0, 7000), + position("2016-01-01 00:29:00.000", 0, 7000)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); ReportUtils reportUtils = new ReportUtils( @@ -262,8 +262,8 @@ public class ReportUtilsTest extends BaseTest { itemStop = iterator.next(); assertEquals(date("2016-01-01 00:09:00.000"), itemStop.getStartTime()); - assertEquals(date("2016-01-01 00:11:00.000"), itemStop.getEndTime()); - assertEquals(120000, itemStop.getDuration()); + assertEquals(date("2016-01-01 00:29:00.000"), itemStop.getEndTime()); + assertEquals(1200000, itemStop.getDuration()); } @@ -332,9 +332,9 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:00:00.000", 2, 0), position("2016-01-01 00:01:00.000", 1, 0), position("2016-01-01 00:02:00.000", 0, 0), - position("2016-01-01 00:03:00.000", 0, 0), - position("2016-01-01 00:04:00.000", 0, 0), - position("2016-01-01 00:05:00.000", 0, 0)); + position("2016-01-01 00:12:00.000", 0, 0), + position("2016-01-01 00:22:00.000", 0, 0), + position("2016-01-01 00:32:00.000", 0, 0)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); ReportUtils reportUtils = new ReportUtils( @@ -349,8 +349,8 @@ public class ReportUtilsTest extends BaseTest { StopReportItem itemStop = result.iterator().next(); assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getStartTime()); - assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getEndTime()); - assertEquals(180000, itemStop.getDuration()); + assertEquals(date("2016-01-01 00:32:00.000"), itemStop.getEndTime()); + assertEquals(1800000, itemStop.getDuration()); } -- cgit v1.2.3 From 9aef1bfcffa0750ba0771dd1af2ffe8667547b3a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Feb 2023 16:30:21 -0800 Subject: Support GPTXT format --- .../org/traccar/protocol/T55ProtocolDecoder.java | 40 +++++++++++++++++++++- .../traccar/protocol/T55ProtocolDecoderTest.java | 3 ++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java index 3be161fb8..4db76f601 100644 --- a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -150,6 +150,18 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { .number("xx") // checksum .compile(); + private static final Pattern PATTERN_GPTXT = new PatternBuilder() + .text("$GPTXT,") + .text("NET,") + .number("(d+),") // device id + .expression("([^,]+),") // network operator + .number("(-d+),") // rssi + .number("(d+) ") // mcc + .number("(d+)") // mnc + .text("*") + .number("xx") // checksum + .compile(); + private Position position = null; private Position decodeGprmc( @@ -328,6 +340,30 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeGptxt(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_GPTXT, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + + getLastLocation(position, null); + + position.set(Position.KEY_OPERATOR, parser.next()); + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set("mcc", parser.nextInt()); + position.set("mnc", parser.nextInt()); + + return position; + } + private Position decodePubx(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_PUBX, sentence); @@ -421,6 +457,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { return decodeQze(channel, remoteAddress, sentence); } else if (sentence.startsWith("$PUBX")) { return decodePubx(channel, remoteAddress, sentence); + } else if (sentence.startsWith("$GPTXT")) { + return decodeGptxt(channel, remoteAddress, sentence); } return null; diff --git a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java index 1622f64f2..e04e473bb 100644 --- a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class T55ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new T55ProtocolDecoder(null)); + verifyAttributes(decoder, text( + "$GPTXT,NET,1003,A1,-53,232 01*77")); + verifyPosition(decoder, text( "$PUBX,00,130209.00,3650.51159,N,01346.10602,E,785.947,D3,4.1,5.2,0.163,87.43,-0.054,7.0,0.88,1.21,0.88,24,01012,0*6D")); -- cgit v1.2.3 From 13b6eda9f0808bd829f31c589b90d10296b51a19 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 Feb 2023 09:24:25 -0800 Subject: Add arm64 support --- setup/package.sh | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/setup/package.sh b/setup/package.sh index f17b5fb14..cbfe03cae 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -15,6 +15,7 @@ usage () { echo "Available platforms:" echo " * linux-64" echo " * linux-arm" + echo " * linux-arm64" echo " * windows-64" echo " * other" exit 1 @@ -64,15 +65,18 @@ if [ $PLATFORM = "all" -o $PLATFORM = "windows-64" ]; then check_requirement "Windows 64 Java" "ls OpenJDK*64_windows*.zip" "Missing Windows 64 JDK (https://adoptium.net/)" check_requirement "Wine" "which wine" "Missing wine binary" fi -if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" -o $PLATFORM = "linux-arm" ]; then +if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" -o $PLATFORM = "linux-arm" -o $PLATFORM = "linux-arm64" ]; then check_requirement "Makeself" "which makeself" "Missing makeself binary" fi if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" ]; then - check_requirement "Linux 64 Java" "ls OpenJDK*64_linux*.tar.gz" "Missing Linux 64 JDK (https://adoptium.net/)" + check_requirement "Linux 64 Java" "ls OpenJDK*x64_linux*.tar.gz" "Missing Linux 64 JDK (https://adoptium.net/)" fi if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm" ]; then check_requirement "Linux ARM Java" "ls OpenJDK*arm_linux*.tar.gz" "Missing Linux ARM JDK (https://adoptium.net/)" fi +if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm64" ]; then + check_requirement "Linux 64 Java" "ls OpenJDK*aarch64_linux*.tar.gz" "Missing Linux ARM 64 JDK (https://adoptium.net/)" +fi if [ $PREREQ = false ]; then info "Missing build requirements, aborting..." exit 1 @@ -133,7 +137,7 @@ package_linux () { cp setup.sh out cp traccar.service out - tar -xf OpenJDK*$1_linux*.tar.gz + tar -xf OpenJDK*$2_linux*.tar.gz jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec,jdk.unsupported --output out/jre rm -rf jdk-* makeself --needroot --quiet --notemp out traccar.run "traccar" ./setup.sh @@ -148,22 +152,29 @@ package_linux () { package_linux_64 () { info "Building Linux 64 installer" - package_linux 64 + package_linux 64 x64 ok "Created Linux 64 installer" } package_linux_arm () { info "Building Linux ARM installer" - package_linux arm + package_linux arm arm ok "Created Linux ARM installer" } +package_linux_arm64 () { + info "Building Linux ARM 64 installer" + package_linux arm64 aarch64 + ok "Created Linux ARM 64 installer" +} + prepare case $PLATFORM in all) package_linux_64 package_linux_arm + package_linux_arm64 package_windows package_other ;; @@ -176,6 +187,10 @@ case $PLATFORM in package_linux_arm ;; + linux-arm64) + package_linux_arm64 + ;; + windows-64) package_windows ;; -- cgit v1.2.3 From a88fec16c1b8b2c3592e9d0a8b52ada6e038a81a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 Feb 2023 09:36:39 -0800 Subject: Fix release build job --- .github/workflows/release.yml | 1 + setup/package.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0a9fb2e73..a157037a5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,6 +50,7 @@ jobs: wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_windows_hotspot_17.0.6_10.zip wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_linux_hotspot_17.0.6_10.tar.gz wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_arm_linux_hotspot_17.0.6_10.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.6_10.tar.gz ./package.sh ${{ github.event.inputs.version }} - name: Upload installers working-directory: ./setup diff --git a/setup/package.sh b/setup/package.sh index cbfe03cae..f8ec927eb 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -75,7 +75,7 @@ if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm" ]; then check_requirement "Linux ARM Java" "ls OpenJDK*arm_linux*.tar.gz" "Missing Linux ARM JDK (https://adoptium.net/)" fi if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm64" ]; then - check_requirement "Linux 64 Java" "ls OpenJDK*aarch64_linux*.tar.gz" "Missing Linux ARM 64 JDK (https://adoptium.net/)" + check_requirement "Linux ARM 64 Java" "ls OpenJDK*aarch64_linux*.tar.gz" "Missing Linux ARM 64 JDK (https://adoptium.net/)" fi if [ $PREREQ = false ]; then info "Missing build requirements, aborting..." -- cgit v1.2.3 From 5b77d6297eaf171595ca0eedb50e434eb073c8ac Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 Feb 2023 15:00:29 -0800 Subject: Configurable TopFly responses --- src/main/java/org/traccar/protocol/T800xProtocolDecoder.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index 6e09e6e3b..758716d23 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -20,6 +20,8 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -511,7 +513,9 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { } } - if (type == MSG_ALARM || type == MSG_ALARM_2) { + boolean acknowledgement = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_ACK.withPrefix(getProtocolName()), deviceSession.getDeviceId()); + if (acknowledgement || type == MSG_ALARM || type == MSG_ALARM_2) { sendResponse(channel, header, type, index, imei, alarm); } -- cgit v1.2.3 From dfc546a26f5b7b9486df31ccce812f44bd41168f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 25 Feb 2023 16:12:31 -0800 Subject: Meitrack TA255 battery level --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 5 +++++ src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 5c5ba4be4..3acd87b8f 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -553,6 +553,11 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // alarm type buf.skipBytes(length - 2); break; + case 0xFEA8: + buf.readUnsignedByte(); // battery status + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + buf.readUnsignedByte(); // battery alert + break; default: buf.skipBytes(length); break; diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 419eddf63..853345521 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "2424663137302c3836353431333035303839313733372c4343452c00000000010088001800050501060907101400150008080000091c000a18000b1e001606001a0000402300fe9000000602d5fe5ffe038f2a1f0904102c8d2b0cd23f02000df03203001c01000000050e0cf90101003170017ac80892ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501010000002a36430d0a"), + Position.KEY_BATTERY_LEVEL, 77); + verifyAttribute(decoder, binary( "24245b3131342c3836343630363034343939333938372c4343452c0000000001005000130006012305000600070f1b004702060800000900000a00000b0000199d011a00000602d179570103b25ccc0604cf04862b0cc65b01000da4090d001c01000000010e0ccc010000b627be11000000002a41300d0a"), Position.KEY_LOCK, true); -- cgit v1.2.3 From 0f5c17535ff8a3bd7a8c8a0616535077e5c72d39 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 25 Feb 2023 16:17:43 -0800 Subject: Remove unnecessary conversion --- src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java index ddd669b36..b83d24f17 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java @@ -130,7 +130,7 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { int index = buf.readUnsignedShortLE(); String id = String.format("%08d%07d", buf.readUnsignedIntLE(), buf.readUnsignedIntLE()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); if (deviceSession == null) { return null; } -- cgit v1.2.3 From 9a1cbeb7b754b0147d8ccbc334849fac087d7cda Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 25 Feb 2023 22:11:51 -0800 Subject: Meitrack TA255 battery level --- .../java/org/traccar/protocol/MeitrackProtocolDecoder.java | 11 +++++++++-- .../org/traccar/protocol/MeitrackProtocolDecoderTest.java | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 3acd87b8f..3f1f7f506 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -554,8 +554,15 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(length - 2); break; case 0xFEA8: - buf.readUnsignedByte(); // battery status - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + if (buf.readUnsignedByte() > 0) { + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + } else { + buf.readUnsignedByte(); + } + buf.readUnsignedByte(); // battery 2 status + buf.readUnsignedByte(); // battery 2 level + buf.readUnsignedByte(); // battery 3 status + buf.readUnsignedByte(); // battery 3 level buf.readUnsignedByte(); // battery alert break; default: diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 853345521..ec45933a3 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -12,7 +12,7 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); verifyAttribute(decoder, binary( - "2424663137302c3836353431333035303839313733372c4343452c00000000010088001800050501060907101400150008080000091c000a18000b1e001606001a0000402300fe9000000602d5fe5ffe038f2a1f0904102c8d2b0cd23f02000df03203001c01000000050e0cf90101003170017ac80892ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501010000002a36430d0a"), + "2424593434312c3836353431333035303839313733372c4343452c00000000030088001800050501061607191400150008080000098e000a05000b0c001608001a0000402300fe9000000602c3fe5ffe03e22a1f0904e6688d2b0cd94002000d5f6f03001c01000000050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000083001700050501061607191400150008080000098e000a05000b0c001608001a0000405100fe9000000502c3fe5ffe03e22a1f0904e6688d2b0cd94002000d606f0300050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000088001800050501061607151400150008080000098e000a05000b0c001607001a0000402300fe9000000602c3fe5ffe03e22a1f0904f0688d2b0cd94002000d696f03001c01000000050e0cf901010032700298c80897ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501000000002a36320d0a"), Position.KEY_BATTERY_LEVEL, 77); verifyAttribute(decoder, binary( -- cgit v1.2.3 From 5284faae8ce9ed077035167063c8d2977d06a8fd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Feb 2023 10:49:24 -0800 Subject: Add cloud-init example --- setup/cloud-init.yaml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 setup/cloud-init.yaml diff --git a/setup/cloud-init.yaml b/setup/cloud-init.yaml new file mode 100644 index 000000000..4ca2e3ed2 --- /dev/null +++ b/setup/cloud-init.yaml @@ -0,0 +1,29 @@ +#cloud-config + +write_files: + - content: | + + + + + ./conf/default.xml + + com.mysql.jdbc.Driver + jdbc:mysql://localhost/traccar?serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false&allowMultiQueries=true&autoReconnect=true&useUnicode=yes&characterEncoding=UTF-8&sessionVariables=sql_mode='' + root + root + + + path: /root/traccar.xml + +package_update: true +packages: + - unzip + - mysql-server + +runcmd: + - mysql -u root --execute="ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES; CREATE DATABASE traccar;" + - wget https://www.traccar.org/download/traccar-linux-64-latest.zip + - unzip traccar-linux-*.zip && ./traccar.run + - cp /root/traccar.xml /opt/traccar/conf/ + - service traccar start -- cgit v1.2.3 From 3331593759a21a1fa36cb64332e14828f7e522f0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Feb 2023 19:31:44 -0800 Subject: Fix alarm and driving behavior --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index d0bbeebb5..f79641bcf 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -847,7 +847,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x03: count = buf.readUnsignedByte(); for (int i = 0; i < count; i++) { - int id = buf.readUnsignedShort(); + int id = buf.readUnsignedByte(); int length = buf.readUnsignedByte(); switch (id) { case 0x1A: diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index e91c84d79..04c3a8cd3 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,9 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyPosition(decoder, binary( + "7e0900001f4f07788ef87d000cf0230223150215010203013800000c000b029dc58c04b99b60230223171822507e")); + verifyPosition(decoder, binary( "7e0200004107904226220608ca0000010000000010031dac0d004864f30000000000002212291003220104000179a7300107310100eb17000300e151000300e304000b00d801041edf340000306b007e")); -- cgit v1.2.3 From 01ca9d91616d148db30333ae79d3bf3fc13fc1e8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 1 Mar 2023 16:21:45 -0800 Subject: Add T24 M2MV2 response --- .../traccar/protocol/TramigoProtocolDecoder.java | 29 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java index b83d24f17..4a9a9a58f 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java @@ -20,6 +20,7 @@ import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -123,23 +124,45 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { } - private Position decode04(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws ParseException { + private Position decode04(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { buf.readUnsignedShortLE(); // length buf.readUnsignedShortLE(); // checksum int index = buf.readUnsignedShortLE(); + long id1 = buf.readUnsignedIntLE(); + long id2 = buf.readUnsignedIntLE(); + long time = buf.readUnsignedIntLE(); - String id = String.format("%08d%07d", buf.readUnsignedIntLE(), buf.readUnsignedIntLE()); + String id = String.format("%08d%07d", id1, id2); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); if (deviceSession == null) { return null; } + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x04); // protocol + response.writeShortLE(24); // length + response.writeShortLE(0); // checksum + response.writeShortLE(index); + response.writeIntLE((int) id1); + response.writeIntLE((int) id2); + response.writeIntLE((int) time); + + response.writeByte(0xff); // acknowledgement + response.writeShortLE(index); + response.writeShortLE(0); // success + + response.setShortLE(3, Checksum.crc16(Checksum.CRC16_CCITT_FALSE, response.nioBuffer())); + + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); position.set(Position.KEY_INDEX, index); - position.setDeviceTime(new Date(buf.readUnsignedIntLE() * 1000)); + position.setDeviceTime(new Date(time * 1000)); while (buf.isReadable()) { int type = buf.readUnsignedByte(); -- cgit v1.2.3 From 847e581a4846994474a3116fc17fc16bde658f00 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 2 Mar 2023 14:49:18 -0800 Subject: Decode full IMEI number --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index f79641bcf..3945b86a3 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -169,7 +169,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } else { long imei = id.getUnsignedShort(0); imei = (imei << 32) + id.getUnsignedInt(2); - return String.valueOf(imei); + return String.valueOf(imei) + Checksum.luhn(imei); } } -- cgit v1.2.3 From 6019dd4996fd19fdc9cc52d0e16d66b0397988a0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 2 Mar 2023 16:14:34 -0800 Subject: Support Redis forwarding --- build.gradle | 1 + src/main/java/org/traccar/MainModule.java | 3 ++ .../traccar/forward/PositionForwarderRedis.java | 50 ++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/main/java/org/traccar/forward/PositionForwarderRedis.java diff --git a/build.gradle b/build.gradle index 27ab1333b..d452fccca 100644 --- a/build.gradle +++ b/build.gradle @@ -83,6 +83,7 @@ dependencies { implementation "com.amazonaws:aws-java-sdk-sns:1.12.399" implementation "org.apache.kafka:kafka-clients:3.3.2" implementation "com.hivemq:hivemq-mqtt-client:1.3.0" + implementation 'redis.clients:jedis:4.3.1' implementation "com.google.firebase:firebase-admin:9.1.1" testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:4.+" diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index ae637b455..96928b295 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -41,6 +41,7 @@ import org.traccar.forward.EventForwarderMqtt; import org.traccar.forward.PositionForwarder; import org.traccar.forward.PositionForwarderJson; import org.traccar.forward.PositionForwarderKafka; +import org.traccar.forward.PositionForwarderRedis; import org.traccar.forward.PositionForwarderUrl; import org.traccar.geocoder.AddressFormat; import org.traccar.geocoder.BanGeocoder; @@ -348,6 +349,8 @@ public class MainModule extends AbstractModule { return new PositionForwarderJson(config, client, objectMapper); case "kafka": return new PositionForwarderKafka(config, objectMapper); + case "redis": + return new PositionForwarderRedis(config, objectMapper); default: return new PositionForwarderUrl(config, client, objectMapper); } diff --git a/src/main/java/org/traccar/forward/PositionForwarderRedis.java b/src/main/java/org/traccar/forward/PositionForwarderRedis.java new file mode 100644 index 000000000..539d247b6 --- /dev/null +++ b/src/main/java/org/traccar/forward/PositionForwarderRedis.java @@ -0,0 +1,50 @@ +/* + * 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.forward; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import redis.clients.jedis.Jedis; + +public class PositionForwarderRedis implements PositionForwarder { + + private final String url; + + private final ObjectMapper objectMapper; + + public PositionForwarderRedis(Config config, ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + this.url = config.getString(Keys.FORWARD_URL); + } + + @Override + public void forward(PositionData positionData, ResultHandler resultHandler) { + + try { + String key = "positions." + positionData.getDevice().getUniqueId(); + String value = objectMapper.writeValueAsString(positionData.getPosition()); + try (Jedis jedis = new Jedis(url)) { + jedis.lpush(key, value); + } + resultHandler.onResult(true, null); + } catch (JsonProcessingException e) { + resultHandler.onResult(false, e); + } + } + +} -- cgit v1.2.3 From d80bf8c6b4e320ec03c0ed31fa460f636f5c6358 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 3 Mar 2023 08:50:31 -0800 Subject: Transparent type response (fix #5040) --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 3945b86a3..d6deafe17 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -294,6 +294,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } else if (type == MSG_TRANSPARENT) { + sendGeneralResponse(channel, remoteAddress, id, type, index); + return decodeTransparent(deviceSession, buf); } -- cgit v1.2.3 From 240fa0061368d27d950443ebf571aa2b6bf9dae3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 6 Mar 2023 09:43:30 -0800 Subject: Explicit switch cases --- src/main/java/org/traccar/MainModule.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 96928b295..ae42d6712 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -333,6 +333,7 @@ public class MainModule extends AbstractModule { return new EventForwarderKafka(config, objectMapper); case "mqtt": return new EventForwarderMqtt(config, objectMapper); + case "json": default: return new EventForwarderJson(config, client); } @@ -351,6 +352,7 @@ public class MainModule extends AbstractModule { return new PositionForwarderKafka(config, objectMapper); case "redis": return new PositionForwarderRedis(config, objectMapper); + case "url": default: return new PositionForwarderUrl(config, client, objectMapper); } -- cgit v1.2.3 From 5505721ed5327eb65cfbbf64ad95bc956d588ba4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 6 Mar 2023 10:56:23 -0800 Subject: Upgrade junit framework --- build.gradle | 4 +- src/test/java/org/traccar/ProtocolTest.java | 73 +++++++++++----------- .../java/org/traccar/calendar/CalendarTest.java | 4 +- src/test/java/org/traccar/config/ConfigTest.java | 4 +- .../java/org/traccar/database/GroupTreeTest.java | 4 +- .../traccar/forward/PositionForwarderUrlTest.java | 4 +- .../org/traccar/geocoder/AddressFormatTest.java | 4 +- .../java/org/traccar/geocoder/GeocoderTest.java | 32 +++++----- .../org/traccar/geofence/GeofenceCircleTest.java | 8 +-- .../org/traccar/geofence/GeofencePolygonTest.java | 8 +-- .../org/traccar/geofence/GeofencePolylineTest.java | 8 +-- .../geolocation/GeolocationProviderTest.java | 10 +-- .../traccar/handler/ComputedAttributesTest.java | 4 +- .../org/traccar/handler/DistanceHandlerTest.java | 4 +- .../org/traccar/handler/FilterHandlerTest.java | 12 ++-- .../org/traccar/handler/MotionHandlerTest.java | 4 +- .../handler/events/AlertEventHandlerTest.java | 6 +- .../events/CommandResultEventHandlerTest.java | 6 +- .../handler/events/IgnitionEventHandlerTest.java | 4 +- .../events/MaintenanceEventHandlerTest.java | 4 +- .../handler/events/MotionEventHandlerTest.java | 6 +- .../handler/events/OverspeedEventHandlerTest.java | 8 +-- src/test/java/org/traccar/helper/BcdUtilTest.java | 4 +- .../java/org/traccar/helper/BitBufferTest.java | 4 +- src/test/java/org/traccar/helper/BitUtilTest.java | 8 +-- .../java/org/traccar/helper/BufferUtilTest.java | 4 +- src/test/java/org/traccar/helper/ChecksumTest.java | 4 +- .../java/org/traccar/helper/DateBuilderTest.java | 4 +- src/test/java/org/traccar/helper/DateUtilTest.java | 4 +- .../org/traccar/helper/DistanceCalculatorTest.java | 4 +- src/test/java/org/traccar/helper/LogTest.java | 4 +- .../java/org/traccar/helper/ObdDecoderTest.java | 4 +- .../org/traccar/helper/PatternBuilderTest.java | 4 +- .../java/org/traccar/helper/PatternUtilTest.java | 8 +-- .../java/org/traccar/helper/ServletHelperTest.java | 4 +- .../notification/NotificiationMailTest.java | 6 +- .../org/traccar/protocol/AdmFrameDecoderTest.java | 2 +- .../traccar/protocol/AdmProtocolDecoderTest.java | 2 +- .../traccar/protocol/AdmProtocolEncoderTest.java | 4 +- .../traccar/protocol/AisProtocolDecoderTest.java | 2 +- .../protocol/AlematicsProtocolDecoderTest.java | 2 +- .../protocol/AnytrekProtocolDecoderTest.java | 2 +- .../traccar/protocol/ApelProtocolDecoderTest.java | 2 +- .../traccar/protocol/AplicomFrameDecoderTest.java | 4 +- .../protocol/AplicomProtocolDecoderTest.java | 2 +- .../protocol/AppelloProtocolDecoderTest.java | 2 +- .../protocol/AquilaProtocolDecoderTest.java | 2 +- .../protocol/Ardi01ProtocolDecoderTest.java | 2 +- .../protocol/ArknavProtocolDecoderTest.java | 2 +- .../protocol/ArknavX8ProtocolDecoderTest.java | 2 +- .../protocol/ArmoliProtocolDecoderTest.java | 2 +- .../protocol/ArnaviBinaryProtocolDecoderTest.java | 2 +- .../traccar/protocol/ArnaviFrameDecoderTest.java | 2 +- .../protocol/ArnaviTextProtocolDecoderTest.java | 2 +- .../traccar/protocol/AstraProtocolDecoderTest.java | 2 +- .../traccar/protocol/At2000FrameDecoderTest.java | 2 +- .../protocol/At2000ProtocolDecoderTest.java | 4 +- .../traccar/protocol/AtrackFrameDecoderTest.java | 2 +- .../protocol/AtrackProtocolDecoderTest.java | 2 +- .../traccar/protocol/AuroProtocolDecoderTest.java | 2 +- .../protocol/AustinNbProtocolDecoderTest.java | 2 +- .../protocol/AutoFonProtocolDecoderTest.java | 2 +- .../protocol/AutoGradeProtocolDecoderTest.java | 2 +- .../protocol/AutoTrackProtocolDecoderTest.java | 2 +- .../traccar/protocol/AvemaProtocolDecoderTest.java | 2 +- .../protocol/Avl301ProtocolDecoderTest.java | 2 +- .../traccar/protocol/B2316ProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/BceFrameDecoderTest.java | 2 +- .../traccar/protocol/BceProtocolDecoderTest.java | 6 +- .../traccar/protocol/BceProtocolEncoderTest.java | 2 +- .../protocol/BlackKiteProtocolDecoderTest.java | 2 +- .../traccar/protocol/BlueProtocolDecoderTest.java | 2 +- .../traccar/protocol/BoxProtocolDecoderTest.java | 2 +- .../traccar/protocol/BstplProtocolDecoderTest.java | 2 +- .../protocol/C2stekProtocolDecoderTest.java | 2 +- .../protocol/CalAmpProtocolDecoderTest.java | 2 +- .../protocol/CarTrackProtocolDecoderTest.java | 2 +- .../protocol/CarscopProtocolDecoderTest.java | 2 +- .../protocol/CastelProtocolDecoderTest.java | 2 +- .../protocol/CastelProtocolEncoderTest.java | 2 +- .../protocol/CautelaProtocolDecoderTest.java | 2 +- .../protocol/CellocatorFrameDecoderTest.java | 2 +- .../protocol/CellocatorProtocolDecoderTest.java | 2 +- .../protocol/CellocatorProtocolEncoderTest.java | 6 +- .../protocol/CguardProtocolDecoderTest.java | 2 +- .../protocol/CityeasyProtocolDecoderTest.java | 2 +- .../protocol/CityeasyProtocolEncoderTest.java | 2 +- .../protocol/ContinentalProtocolDecoderTest.java | 2 +- .../protocol/CradlepointProtocolDecoderTest.java | 2 +- .../traccar/protocol/DingtekFrameDecoderTest.java | 2 +- .../protocol/DingtekProtocolDecoderTest.java | 2 +- .../traccar/protocol/DishaProtocolDecoderTest.java | 2 +- .../protocol/DmtHttpProtocolDecoderTest.java | 2 +- .../traccar/protocol/DmtProtocolDecoderTest.java | 2 +- .../protocol/DolphinProtocolDecoderTest.java | 2 +- .../traccar/protocol/Dsf22FrameDecoderTest.java | 2 +- .../traccar/protocol/Dsf22ProtocolDecoderTest.java | 2 +- .../traccar/protocol/DualcamFrameDecoderTest.java | 2 +- .../protocol/DualcamProtocolDecoderTest.java | 2 +- .../traccar/protocol/DwayProtocolDecoderTest.java | 2 +- .../protocol/EasyTrackProtocolDecoderTest.java | 2 +- .../protocol/EasyTrackProtocolEncoderTest.java | 4 +- .../protocol/EelinkProtocolDecoderTest.java | 2 +- .../protocol/EelinkProtocolEncoderTest.java | 2 +- .../org/traccar/protocol/EgtsFrameDecoderTest.java | 2 +- .../traccar/protocol/EgtsProtocolDecoderTest.java | 2 +- .../protocol/EnforaProtocolDecoderTest.java | 2 +- .../traccar/protocol/EnnfuProtocolDecoderTest.java | 2 +- .../protocol/EnvotechProtocolDecoderTest.java | 2 +- .../traccar/protocol/EsealProtocolDecoderTest.java | 2 +- .../traccar/protocol/EsealProtocolEncoderTest.java | 4 +- .../org/traccar/protocol/EskyFrameDecoderTest.java | 2 +- .../traccar/protocol/EskyProtocolDecoderTest.java | 2 +- .../protocol/ExtremTracProtocolDecoderTest.java | 2 +- .../protocol/FifotrackFrameDecoderTest.java | 2 +- .../protocol/FifotrackProtocolDecoderTest.java | 2 +- .../protocol/FifotrackProtocolEncoderTest.java | 4 +- .../protocol/FlespiProtocolDecoderTest.java | 2 +- .../protocol/FlexApiProtocolDecoderTest.java | 2 +- .../protocol/FlexCommProtocolDecoderTest.java | 2 +- .../FlexibleReportProtocolDecoderTest.java | 2 +- .../protocol/FlextrackProtocolDecoderTest.java | 2 +- .../traccar/protocol/FoxProtocolDecoderTest.java | 2 +- .../protocol/FreedomProtocolDecoderTest.java | 2 +- .../protocol/FreematicsProtocolDecoderTest.java | 2 +- .../protocol/FutureWayFrameDecoderTest.java | 2 +- .../protocol/FutureWayProtocolDecoderTest.java | 2 +- .../traccar/protocol/G1rusProtocolDecoderTest.java | 2 +- .../traccar/protocol/GalileoFrameDecoderTest.java | 4 +- .../protocol/GalileoProtocolDecoderTest.java | 2 +- .../protocol/GalileoProtocolEncoderTest.java | 2 +- .../traccar/protocol/GatorProtocolDecoderTest.java | 4 +- .../traccar/protocol/GenxProtocolDecoderTest.java | 2 +- .../traccar/protocol/Gl100ProtocolDecoderTest.java | 2 +- .../protocol/Gl200BinaryProtocolDecoderTest.java | 2 +- .../traccar/protocol/Gl200FrameDecoderTest.java | 4 +- .../protocol/Gl200TextProtocolDecoderTest.java | 2 +- .../protocol/GlobalSatProtocolDecoderTest.java | 2 +- .../protocol/GlobalSatProtocolEncoderTest.java | 4 +- .../protocol/GlobalstarProtocolDecoderTest.java | 2 +- .../traccar/protocol/GnxProtocolDecoderTest.java | 2 +- .../protocol/GoSafeProtocolDecoderTest.java | 2 +- .../traccar/protocol/GotopProtocolDecoderTest.java | 2 +- .../traccar/protocol/Gps056FrameDecoderTest.java | 4 +- .../protocol/Gps056ProtocolDecoderTest.java | 2 +- .../protocol/Gps103ProtocolDecoderTest.java | 2 +- .../protocol/Gps103ProtocolEncoderTest.java | 4 +- .../protocol/GpsGateProtocolDecoderTest.java | 2 +- .../protocol/GpsMarkerProtocolDecoderTest.java | 2 +- .../protocol/GpsmtaProtocolDecoderTest.java | 2 +- .../traccar/protocol/GranitFrameDecoderTest.java | 4 +- .../protocol/GranitProtocolDecoderTest.java | 2 +- .../traccar/protocol/Gs100ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Gt02ProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/Gt06FrameDecoderTest.java | 2 +- .../traccar/protocol/Gt06ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Gt06ProtocolEncoderTest.java | 2 +- .../traccar/protocol/Gt30ProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/H02FrameDecoderTest.java | 4 +- .../traccar/protocol/H02ProtocolDecoderTest.java | 2 +- .../traccar/protocol/H02ProtocolEncoderTest.java | 8 +-- .../protocol/HaicomProtocolDecoderTest.java | 2 +- .../protocol/HomtecsProtocolDecoderTest.java | 2 +- .../traccar/protocol/HoopoProtocolDecoderTest.java | 2 +- .../traccar/protocol/HuaShengFrameDecoderTest.java | 4 +- .../protocol/HuaShengProtocolDecoderTest.java | 2 +- .../traccar/protocol/HuabaoFrameDecoderTest.java | 2 +- .../protocol/HuabaoProtocolDecoderTest.java | 2 +- .../protocol/HuabaoProtocolEncoderTest.java | 6 +- .../protocol/HunterProProtocolDecoderTest.java | 2 +- .../traccar/protocol/IdplProtocolDecoderTest.java | 2 +- .../protocol/IntellitracProtocolDecoderTest.java | 2 +- .../traccar/protocol/IotmProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/ItsFrameDecoderTest.java | 2 +- .../traccar/protocol/ItsProtocolDecoderTest.java | 2 +- .../traccar/protocol/ItsProtocolEncoderTest.java | 4 +- .../protocol/Ivt401ProtocolDecoderTest.java | 2 +- .../traccar/protocol/JidoProtocolDecoderTest.java | 2 +- .../protocol/JpKorjarProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/JsonFrameDecoderTest.java | 2 +- .../traccar/protocol/Jt600FrameDecoderTest.java | 2 +- .../traccar/protocol/Jt600ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Jt600ProtocolEncoderTest.java | 4 +- .../traccar/protocol/KenjiProtocolDecoderTest.java | 2 +- .../traccar/protocol/KhdProtocolDecoderTest.java | 2 +- .../traccar/protocol/KhdProtocolEncoderTest.java | 2 +- .../org/traccar/protocol/L100FrameDecoderTest.java | 2 +- .../traccar/protocol/L100ProtocolDecoderTest.java | 2 +- .../traccar/protocol/LacakProtocolDecoderTest.java | 2 +- .../protocol/LaipacProtocolDecoderTest.java | 2 +- .../protocol/LeafSpyProtocolDecoderTest.java | 2 +- .../traccar/protocol/M2cProtocolDecoderTest.java | 2 +- .../traccar/protocol/M2mProtocolDecoderTest.java | 2 +- .../protocol/MaestroProtocolDecoderTest.java | 2 +- .../protocol/ManPowerProtocolDecoderTest.java | 2 +- .../protocol/Mavlink2ProtocolDecoderTest.java | 2 +- .../traccar/protocol/MegastekFrameDecoderTest.java | 2 +- .../protocol/MegastekProtocolDecoderTest.java | 2 +- .../traccar/protocol/MeiligaoFrameDecoderTest.java | 6 +- .../protocol/MeiligaoProtocolDecoderTest.java | 2 +- .../protocol/MeiligaoProtocolEncoderTest.java | 2 +- .../traccar/protocol/MeitrackFrameDecoderTest.java | 4 +- .../protocol/MeitrackProtocolDecoderTest.java | 2 +- .../protocol/MeitrackProtocolEncoderTest.java | 4 +- .../protocol/MictrackProtocolDecoderTest.java | 2 +- .../protocol/MilesmateProtocolDecoderTest.java | 2 +- .../protocol/MiniFinderProtocolDecoderTest.java | 2 +- .../protocol/MiniFinderProtocolEncoderTest.java | 4 +- .../protocol/Minifinder2ProtocolDecoderTest.java | 2 +- .../protocol/MobilogixProtocolDecoderTest.java | 2 +- .../protocol/MoovboxProtocolDecoderTest.java | 2 +- .../traccar/protocol/MotorProtocolDecoderTest.java | 2 +- .../traccar/protocol/MtxProtocolDecoderTest.java | 2 +- .../traccar/protocol/MxtProtocolDecoderTest.java | 2 +- .../protocol/NavigilProtocolDecoderTest.java | 2 +- .../traccar/protocol/NavisFrameDecoderTest.java | 2 +- .../traccar/protocol/NavisProtocolDecoderTest.java | 2 +- .../traccar/protocol/NavisetFrameDecoderTest.java | 2 +- .../protocol/NavisetProtocolDecoderTest.java | 2 +- .../protocol/NavtelecomFrameDecoderTest.java | 6 +- .../protocol/NavtelecomProtocolDecoderTest.java | 2 +- .../protocol/NdtpV6ProtocolDecoderTest.java | 2 +- .../traccar/protocol/NeosProtocolDecoderTest.java | 2 +- .../traccar/protocol/NetProtocolDecoderTest.java | 2 +- .../traccar/protocol/NiotProtocolDecoderTest.java | 2 +- .../traccar/protocol/NoranProtocolDecoderTest.java | 2 +- .../traccar/protocol/NoranProtocolEncoderTest.java | 2 +- .../org/traccar/protocol/NvsFrameDecoderTest.java | 4 +- .../traccar/protocol/NvsProtocolDecoderTest.java | 2 +- .../protocol/NyitechProtocolDecoderTest.java | 2 +- .../protocol/ObdDongleProtocolDecoderTest.java | 2 +- .../traccar/protocol/OigoProtocolDecoderTest.java | 2 +- .../traccar/protocol/OkoProtocolDecoderTest.java | 2 +- .../traccar/protocol/OmnicommFrameDecoderTest.java | 2 +- .../protocol/OmnicommProtocolDecoderTest.java | 2 +- .../protocol/OpenGtsProtocolDecoderTest.java | 2 +- .../protocol/OrbcommProtocolDecoderTest.java | 2 +- .../traccar/protocol/OrionProtocolDecoderTest.java | 2 +- .../protocol/OsmAndProtocolDecoderTest.java | 2 +- .../protocol/OutsafeProtocolDecoderTest.java | 2 +- .../protocol/OwnTracksProtocolDecoderTest.java | 2 +- .../protocol/PacificTrackProtocolDecoderTest.java | 4 +- .../protocol/PathAwayProtocolDecoderTest.java | 2 +- .../protocol/PiligrimProtocolDecoderTest.java | 2 +- .../protocol/PluginProtocolDecoderTest.java | 2 +- .../traccar/protocol/PolteProtocolDecoderTest.java | 2 +- .../protocol/PortmanProtocolDecoderTest.java | 2 +- .../protocol/PortmanProtocolEncoderTest.java | 4 +- .../protocol/PretraceProtocolDecoderTest.java | 2 +- .../protocol/PretraceProtocolEncoderTest.java | 4 +- .../protocol/PricolProtocolDecoderTest.java | 2 +- .../protocol/ProgressProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/PstFrameDecoderTest.java | 2 +- .../org/traccar/protocol/PstFrameEncoderTest.java | 2 +- .../traccar/protocol/PstProtocolDecoderTest.java | 2 +- .../traccar/protocol/PstProtocolEncoderTest.java | 2 +- .../traccar/protocol/Pt215ProtocolDecoderTest.java | 2 +- .../protocol/Pt3000ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Pt502FrameDecoderTest.java | 2 +- .../traccar/protocol/Pt502ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Pt502ProtocolEncoderTest.java | 4 +- .../traccar/protocol/Pt60ProtocolDecoderTest.java | 2 +- .../traccar/protocol/R12wProtocolDecoderTest.java | 2 +- .../protocol/RaceDynamicsProtocolDecoderTest.java | 2 +- .../traccar/protocol/RadarProtocolDecoderTest.java | 2 +- .../protocol/RaveonProtocolDecoderTest.java | 2 +- .../protocol/RecodaProtocolDecoderTest.java | 2 +- .../protocol/RetranslatorProtocolDecoderTest.java | 2 +- .../protocol/RfTrackProtocolDecoderTest.java | 2 +- .../traccar/protocol/RitiProtocolDecoderTest.java | 2 +- .../protocol/RoboTrackFrameDecoderTest.java | 2 +- .../protocol/RoboTrackProtocolDecoderTest.java | 2 +- .../traccar/protocol/RstProtocolDecoderTest.java | 2 +- .../protocol/RuptelaProtocolDecoderTest.java | 2 +- .../protocol/RuptelaProtocolEncoderTest.java | 2 +- .../traccar/protocol/S168ProtocolDecoderTest.java | 2 +- .../traccar/protocol/SabertekFrameDecoderTest.java | 4 +- .../protocol/SabertekProtocolDecoderTest.java | 2 +- .../traccar/protocol/SanavProtocolDecoderTest.java | 2 +- .../traccar/protocol/SanulProtocolDecoderTest.java | 2 +- .../protocol/SatsolProtocolDecoderTest.java | 2 +- .../protocol/SigfoxProtocolDecoderTest.java | 2 +- .../traccar/protocol/SiwiProtocolDecoderTest.java | 2 +- .../protocol/SkypatrolProtocolDecoderTest.java | 2 +- .../protocol/SmartSoleProtocolDecoderTest.java | 2 +- .../protocol/SmokeyProtocolDecoderTest.java | 2 +- .../protocol/SolarPoweredProtocolDecoderTest.java | 2 +- .../traccar/protocol/SpotProtocolDecoderTest.java | 2 +- .../protocol/StarLinkProtocolDecoderTest.java | 2 +- .../protocol/StarcomProtocolDecoderTest.java | 2 +- .../protocol/StartekProtocolDecoderTest.java | 2 +- .../protocol/StartekProtocolEncoderTest.java | 4 +- .../traccar/protocol/StbProtocolDecoderTest.java | 2 +- .../protocol/Stl060ProtocolDecoderTest.java | 2 +- .../traccar/protocol/SuntechFrameDecoderTest.java | 2 +- .../protocol/SuntechProtocolDecoderTest.java | 6 +- .../protocol/SupermateProtocolDecoderTest.java | 2 +- .../traccar/protocol/SviasProtocolDecoderTest.java | 2 +- .../protocol/SwiftechProtocolDecoderTest.java | 2 +- .../traccar/protocol/T55ProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/T57FrameDecoderTest.java | 2 +- .../traccar/protocol/T57ProtocolDecoderTest.java | 2 +- .../traccar/protocol/T800xProtocolDecoderTest.java | 2 +- .../traccar/protocol/T800xProtocolEncoderTest.java | 2 +- .../traccar/protocol/TaipProtocolDecoderTest.java | 2 +- .../protocol/TechTltProtocolDecoderTest.java | 2 +- .../protocol/TechtoCruzFrameDecoderTest.java | 4 +- .../protocol/TechtoCruzProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/TekFrameDecoderTest.java | 2 +- .../traccar/protocol/TekProtocolDecoderTest.java | 2 +- .../protocol/TelemaxProtocolDecoderTest.java | 2 +- .../traccar/protocol/TelicFrameDecoderTest.java | 2 +- .../traccar/protocol/TelicProtocolDecoderTest.java | 2 +- .../protocol/TeltonikaFrameDecoderTest.java | 2 +- .../protocol/TeltonikaProtocolDecoderTest.java | 6 +- .../protocol/TeltonikaProtocolEncoderTest.java | 2 +- .../protocol/TeraTrackProtocolDecoderTest.java | 2 +- .../protocol/ThinkPowerProtocolDecoderTest.java | 2 +- .../protocol/ThinkRaceProtocolDecoderTest.java | 2 +- .../protocol/ThurayaProtocolDecoderTest.java | 2 +- .../traccar/protocol/Tk102ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Tk103FrameDecoderTest.java | 2 +- .../traccar/protocol/Tk103ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Tk103ProtocolEncoderTest.java | 4 +- .../traccar/protocol/Tlt2hProtocolDecoderTest.java | 2 +- .../traccar/protocol/TlvProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/TmgFrameDecoderTest.java | 2 +- .../traccar/protocol/TmgProtocolDecoderTest.java | 2 +- .../protocol/TopflytechProtocolDecoderTest.java | 2 +- .../traccar/protocol/TopinProtocolDecoderTest.java | 2 +- .../traccar/protocol/TopinProtocolEncoderTest.java | 2 +- .../traccar/protocol/TotemFrameDecoderTest.java | 2 +- .../traccar/protocol/TotemProtocolDecoderTest.java | 2 +- .../traccar/protocol/TotemProtocolEncoderTest.java | 4 +- .../traccar/protocol/Tr20ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Tr900ProtocolDecoderTest.java | 2 +- .../protocol/TrackboxProtocolDecoderTest.java | 2 +- .../protocol/TrakMateProtocolDecoderTest.java | 2 +- .../traccar/protocol/TramigoFrameDecoderTest.java | 2 +- .../protocol/TramigoProtocolDecoderTest.java | 2 +- .../traccar/protocol/TrvProtocolDecoderTest.java | 2 +- .../protocol/Tt8850ProtocolDecoderTest.java | 2 +- .../traccar/protocol/TytanProtocolDecoderTest.java | 2 +- .../traccar/protocol/TzoneProtocolDecoderTest.java | 2 +- .../traccar/protocol/UlbotechFrameDecoderTest.java | 2 +- .../protocol/UlbotechProtocolDecoderTest.java | 2 +- .../protocol/UlbotechProtocolEncoderTest.java | 2 +- .../traccar/protocol/UproProtocolDecoderTest.java | 2 +- .../traccar/protocol/UuxProtocolDecoderTest.java | 2 +- .../traccar/protocol/V680ProtocolDecoderTest.java | 2 +- .../protocol/VisiontekProtocolDecoderTest.java | 2 +- .../traccar/protocol/VnetProtocolDecoderTest.java | 2 +- .../traccar/protocol/Vt200FrameDecoderTest.java | 2 +- .../traccar/protocol/Vt200ProtocolDecoderTest.java | 2 +- .../traccar/protocol/VtfmsFrameDecoderTest.java | 4 +- .../traccar/protocol/VtfmsProtocolDecoderTest.java | 2 +- .../traccar/protocol/WatchFrameDecoderTest.java | 2 +- .../traccar/protocol/WatchProtocolDecoderTest.java | 2 +- .../traccar/protocol/WatchProtocolEncoderTest.java | 2 +- .../protocol/WialonProtocolDecoderTest.java | 2 +- .../org/traccar/protocol/WliFrameDecoderTest.java | 2 +- .../traccar/protocol/WliProtocolDecoderTest.java | 2 +- .../traccar/protocol/WondexFrameDecoderTest.java | 6 +- .../protocol/WondexProtocolDecoderTest.java | 2 +- .../protocol/WondexProtocolEncoderTest.java | 4 +- .../protocol/WristbandProtocolDecoderTest.java | 2 +- .../traccar/protocol/Xexun2FrameDecoderTest.java | 2 +- .../traccar/protocol/Xexun2FrameEncoderTest.java | 2 +- .../protocol/Xexun2ProtocolDecoderTest.java | 2 +- .../protocol/Xexun2ProtocolEncoderTest.java | 2 +- .../traccar/protocol/XexunFrameDecoderTest.java | 2 +- .../traccar/protocol/XexunProtocolDecoderTest.java | 2 +- .../traccar/protocol/XirgoProtocolDecoderTest.java | 2 +- .../traccar/protocol/XirgoProtocolEncoderTest.java | 4 +- .../traccar/protocol/Xrb28ProtocolDecoderTest.java | 2 +- .../traccar/protocol/Xrb28ProtocolEncoderTest.java | 4 +- .../traccar/protocol/Xt013ProtocolDecoderTest.java | 2 +- .../protocol/Xt2400ProtocolDecoderTest.java | 2 +- .../traccar/protocol/YwtProtocolDecoderTest.java | 2 +- .../java/org/traccar/reports/ReportUtilsTest.java | 14 ++--- .../speedlimit/OverpassSpeedLimitProviderTest.java | 10 +-- src/test/java/org/traccar/web/WebServerTest.java | 2 +- 382 files changed, 552 insertions(+), 553 deletions(-) diff --git a/build.gradle b/build.gradle index d452fccca..17728e0ce 100644 --- a/build.gradle +++ b/build.gradle @@ -83,9 +83,9 @@ dependencies { implementation "com.amazonaws:aws-java-sdk-sns:1.12.399" implementation "org.apache.kafka:kafka-clients:3.3.2" implementation "com.hivemq:hivemq-mqtt-client:1.3.0" - implementation 'redis.clients:jedis:4.3.1' + implementation "redis.clients:jedis:4.3.1" implementation "com.google.firebase:firebase-admin:9.1.1" - testImplementation "junit:junit:4.13.2" + testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.2" testImplementation "org.mockito:mockito-core:4.+" } diff --git a/src/test/java/org/traccar/ProtocolTest.java b/src/test/java/org/traccar/ProtocolTest.java index 5e37f44b9..ce005e93f 100644 --- a/src/test/java/org/traccar/ProtocolTest.java +++ b/src/test/java/org/traccar/ProtocolTest.java @@ -26,11 +26,11 @@ import java.util.List; import java.util.Map; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ProtocolTest extends BaseTest { @@ -112,7 +112,7 @@ public class ProtocolTest extends BaseTest { Object decodedObject = decoder.decode(null, null, object); Position position; if (decodedObject instanceof Collection) { - position = (Position) ((Collection) decodedObject).iterator().next(); + position = (Position) ((Collection) decodedObject).iterator().next(); } else { position = (Position) decodedObject; } @@ -155,11 +155,11 @@ public class ProtocolTest extends BaseTest { private void verifyDecodedList(Object decodedObject, boolean checkLocation, Position expected) { - assertNotNull("list is null", decodedObject); - assertTrue("not a list", decodedObject instanceof List); - assertFalse("list is empty", ((List) decodedObject).isEmpty()); + assertNotNull(decodedObject, "list is null"); + assertTrue(decodedObject instanceof List, "not a list"); + assertFalse(((List) decodedObject).isEmpty(), "list is empty"); - for (Object item : (List) decodedObject) { + for (Object item : (List) decodedObject) { verifyDecodedPosition(item, checkLocation, false, expected); } @@ -167,8 +167,8 @@ public class ProtocolTest extends BaseTest { private void verifyDecodedPosition(Object decodedObject, boolean checkLocation, boolean checkAttributes, Position expected) { - assertNotNull("position is null", decodedObject); - assertTrue("not a position", decodedObject instanceof Position); + assertNotNull(decodedObject, "position is null"); + assertTrue(decodedObject instanceof Position, "not a position"); Position position = (Position) decodedObject; @@ -181,45 +181,44 @@ public class ProtocolTest extends BaseTest { dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); assertEquals("time", dateFormat.format(expected.getFixTime()), dateFormat.format(position.getFixTime())); } - assertEquals("valid", expected.getValid(), position.getValid()); - assertEquals("latitude", expected.getLatitude(), position.getLatitude(), 0.00001); - assertEquals("longitude", expected.getLongitude(), position.getLongitude(), 0.00001); + assertEquals(expected.getValid(), position.getValid(), "valid"); + assertEquals(expected.getLatitude(), position.getLatitude(), 0.00001, "latitude"); + assertEquals(expected.getLongitude(), position.getLongitude(), 0.00001, "longitude"); } else { assertNotNull(position.getServerTime()); assertNotNull(position.getFixTime()); - assertTrue("year > 1999", position.getFixTime().after(new Date(915148800000L))); - assertTrue("time < +25 hours", - position.getFixTime().getTime() < System.currentTimeMillis() + 25 * 3600000); + assertTrue(position.getFixTime().after(new Date(915148800000L)), "year > 1999"); + assertTrue(position.getFixTime().getTime() < System.currentTimeMillis() + 25 * 3600000, "time < +25 h"); - assertTrue("latitude >= -90", position.getLatitude() >= -90); - assertTrue("latitude <= 90", position.getLatitude() <= 90); + assertTrue(position.getLatitude() >= -90, "latitude >= -90"); + assertTrue(position.getLatitude() <= 90, "latitude <= 90"); - assertTrue("longitude >= -180", position.getLongitude() >= -180); - assertTrue("longitude <= 180", position.getLongitude() <= 180); + assertTrue(position.getLongitude() >= -180, "longitude >= -180"); + assertTrue(position.getLongitude() <= 180, "longitude <= 180"); } - assertTrue("altitude >= -12262", position.getAltitude() >= -12262); - assertTrue("altitude <= 18000", position.getAltitude() <= 18000); + assertTrue(position.getAltitude() >= -12262, "altitude >= -12262"); + assertTrue(position.getAltitude() <= 18000, "altitude <= 18000"); - assertTrue("speed >= 0", position.getSpeed() >= 0); - assertTrue("speed <= 869", position.getSpeed() <= 869); + assertTrue(position.getSpeed() >= 0, "speed >= 0"); + assertTrue(position.getSpeed() <= 869, "speed <= 869"); - assertTrue("course >= 0", position.getCourse() >= 0); - assertTrue("course <= 360", position.getCourse() <= 360); + assertTrue(position.getCourse() >= 0, "course >= 0"); + assertTrue(position.getCourse() <= 360, "course <= 360"); - assertNotNull("protocol is null", position.getProtocol()); + assertNotNull(position.getProtocol(), "protocol is null"); - assertTrue("deviceId > 0", position.getDeviceId() > 0); + assertTrue(position.getDeviceId() > 0, "deviceId > 0"); } Map attributes = position.getAttributes(); if (checkAttributes) { - assertFalse("no attributes", attributes.isEmpty()); + assertFalse(attributes.isEmpty(), "no attributes"); } if (attributes.containsKey(Position.KEY_INDEX)) { @@ -331,11 +330,11 @@ public class ProtocolTest extends BaseTest { } private void checkInteger(Object value, int min, int max) { - assertNotNull("value is null", value); - assertTrue("not int or long", value instanceof Integer || value instanceof Long); + assertNotNull(value, "value is null"); + assertTrue(value instanceof Integer || value instanceof Long, "not int or long"); long number = ((Number) value).longValue(); - assertTrue("value too low", number >= min); - assertTrue("value too high", number <= max); + assertTrue(number >= min, "value too low"); + assertTrue(number <= max, "value too high"); } protected void verifyCommand( @@ -344,8 +343,8 @@ public class ProtocolTest extends BaseTest { } protected void verifyFrame(ByteBuf expected, Object object) { - assertNotNull("buffer is null", object); - assertTrue("not a buffer", object instanceof ByteBuf); + assertNotNull(object, "buffer is null"); + assertTrue(object instanceof ByteBuf, "not a buffer"); assertEquals(ByteBufUtil.hexDump(expected), ByteBufUtil.hexDump((ByteBuf) object)); } diff --git a/src/test/java/org/traccar/calendar/CalendarTest.java b/src/test/java/org/traccar/calendar/CalendarTest.java index def67ff76..6f4b30370 100644 --- a/src/test/java/org/traccar/calendar/CalendarTest.java +++ b/src/test/java/org/traccar/calendar/CalendarTest.java @@ -1,7 +1,7 @@ package org.traccar.calendar; import net.fortuna.ical4j.data.ParserException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.model.Calendar; import java.io.IOException; @@ -11,7 +11,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class CalendarTest { diff --git a/src/test/java/org/traccar/config/ConfigTest.java b/src/test/java/org/traccar/config/ConfigTest.java index 8ba6dace6..f48e79acf 100644 --- a/src/test/java/org/traccar/config/ConfigTest.java +++ b/src/test/java/org/traccar/config/ConfigTest.java @@ -1,8 +1,8 @@ package org.traccar.config; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ConfigTest { diff --git a/src/test/java/org/traccar/database/GroupTreeTest.java b/src/test/java/org/traccar/database/GroupTreeTest.java index b547aab60..7c0d478f8 100644 --- a/src/test/java/org/traccar/database/GroupTreeTest.java +++ b/src/test/java/org/traccar/database/GroupTreeTest.java @@ -1,13 +1,13 @@ package org.traccar.database; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.model.Device; import org.traccar.model.Group; import java.util.ArrayList; import java.util.Collection; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class GroupTreeTest { diff --git a/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java b/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java index 522958052..f0e354620 100644 --- a/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java +++ b/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java @@ -1,13 +1,13 @@ package org.traccar.forward; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Device; import org.traccar.model.Position; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/src/test/java/org/traccar/geocoder/AddressFormatTest.java b/src/test/java/org/traccar/geocoder/AddressFormatTest.java index 0cc5168ef..b3a248bb3 100644 --- a/src/test/java/org/traccar/geocoder/AddressFormatTest.java +++ b/src/test/java/org/traccar/geocoder/AddressFormatTest.java @@ -1,8 +1,8 @@ package org.traccar.geocoder; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class AddressFormatTest { diff --git a/src/test/java/org/traccar/geocoder/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java index ff33b1f1c..7ee0e68d0 100644 --- a/src/test/java/org/traccar/geocoder/GeocoderTest.java +++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java @@ -1,13 +1,13 @@ package org.traccar.geocoder; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import java.util.Locale; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class GeocoderTest { @@ -17,7 +17,7 @@ public class GeocoderTest { private final Client client = ClientBuilder.newClient(); - @Ignore + @Disabled @Test public void testGoogle() { Geocoder geocoder = new GoogleGeocoder(client, null, null, 0, new AddressFormat()); @@ -25,7 +25,7 @@ public class GeocoderTest { assertEquals("1 Ibn Shaprut St, Jerusalem, Jerusalem District, IL", address); } - @Ignore + @Disabled @Test public void testNominatim() { Geocoder geocoder = new NominatimGeocoder(client, null, null, null, 0, new AddressFormat()); @@ -33,7 +33,7 @@ public class GeocoderTest { assertEquals("35 West 9th Street, NYC, New York, US", address); } - @Ignore + @Disabled @Test public void testGisgraphy() { Geocoder geocoder = new GisgraphyGeocoder(client, null, 0, new AddressFormat()); @@ -41,7 +41,7 @@ public class GeocoderTest { assertEquals("Rue du Jardinet, Paris, ÃŽle-de-France, FR", address); } - @Ignore + @Disabled @Test public void testOpenCage() { Geocoder geocoder = new OpenCageGeocoder( @@ -50,7 +50,7 @@ public class GeocoderTest { assertEquals("Charleston Road, California, US", address); } - @Ignore + @Disabled @Test public void testGeocodeFarm() { Geocoder geocoder = new GeocodeFarmGeocoder(client, null, null, 0, new AddressFormat()); @@ -58,7 +58,7 @@ public class GeocoderTest { assertEquals("Estrella Avenue, Arcadia, California, United States", address); } - @Ignore + @Disabled @Test public void testGeocodeXyz() { Geocoder geocoder = new GeocodeXyzGeocoder(client, null, 0, new AddressFormat()); @@ -66,7 +66,7 @@ public class GeocoderTest { assertEquals("605 ESTRELLA AVE, ARCADIA, California United States of America, US", address); } - @Ignore + @Disabled @Test public void testBan() { Geocoder geocoder = new BanGeocoder(client, 0, new AddressFormat("%f [%d], %c")); @@ -74,7 +74,7 @@ public class GeocoderTest { assertEquals("8 Avenue Gustave Eiffel 75007 Paris [75, Paris, ÃŽle-de-France], FR", address); } - @Ignore + @Disabled @Test public void testHere() { Geocoder geocoder = new HereGeocoder(client, null, "", "", null, 0, new AddressFormat()); @@ -82,7 +82,7 @@ public class GeocoderTest { assertEquals("6 Avenue Gustave Eiffel, Paris, ÃŽle-de-France, FRA", address); } - @Ignore + @Disabled @Test public void testMapmyIndia() { Geocoder geocoder = new MapmyIndiaGeocoder(client, "", "", 0, new AddressFormat("%f")); @@ -90,7 +90,7 @@ public class GeocoderTest { assertEquals("New Delhi, Delhi. 1 m from India Gate pin-110001 (India)", address); } - @Ignore + @Disabled @Test public void testPositionStack() { Geocoder geocoder = new PositionStackGeocoder(client, "", 0, new AddressFormat("%f")); @@ -98,7 +98,7 @@ public class GeocoderTest { assertEquals("India Gate, New Delhi, India", address); } - @Ignore + @Disabled @Test public void testMapbox() { Geocoder geocoder = new MapboxGeocoder(client, "", 0, new AddressFormat("%f")); @@ -106,7 +106,7 @@ public class GeocoderTest { assertEquals("120 East 13th Street, New York, New York 10003, United States", address); } - @Ignore + @Disabled @Test public void testMapTiler() { Geocoder geocoder = new MapTilerGeocoder(client, "", 0, new AddressFormat()); @@ -114,7 +114,7 @@ public class GeocoderTest { assertEquals("East 13th Street, New York City, New York, United States", address); } - @Ignore + @Disabled @Test public void testGeoapify() { Geocoder geocoder = new GeoapifyGeocoder(client, "", null, 0, new AddressFormat()); diff --git a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java index 9a02cec76..106b041fc 100644 --- a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java +++ b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java @@ -1,12 +1,12 @@ package org.traccar.geofence; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.text.ParseException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class GeofenceCircleTest { diff --git a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java index 5baecd771..bbf19cc38 100644 --- a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java +++ b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java @@ -1,12 +1,12 @@ package org.traccar.geofence; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.text.ParseException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class GeofencePolygonTest { diff --git a/src/test/java/org/traccar/geofence/GeofencePolylineTest.java b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java index b7ee14510..9b7bbb7d1 100644 --- a/src/test/java/org/traccar/geofence/GeofencePolylineTest.java +++ b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java @@ -1,15 +1,15 @@ package org.traccar.geofence; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Geofence; import java.text.ParseException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java index 876b6b688..3e0729dff 100644 --- a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java +++ b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java @@ -1,7 +1,7 @@ package org.traccar.geolocation; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.model.CellTower; import org.traccar.model.Network; @@ -9,14 +9,14 @@ import org.traccar.model.Network; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class GeolocationProviderTest extends BaseTest { private final Client client = ClientBuilder.newClient(); - @Ignore + @Disabled @Test public void testMozilla() throws Exception { MozillaGeolocationProvider provider = new MozillaGeolocationProvider(client, null); diff --git a/src/test/java/org/traccar/handler/ComputedAttributesTest.java b/src/test/java/org/traccar/handler/ComputedAttributesTest.java index 0beef9c57..e2af703c2 100644 --- a/src/test/java/org/traccar/handler/ComputedAttributesTest.java +++ b/src/test/java/org/traccar/handler/ComputedAttributesTest.java @@ -1,13 +1,13 @@ package org.traccar.handler; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.config.Config; import org.traccar.model.Attribute; import org.traccar.model.Position; import java.util.Date; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ComputedAttributesTest { diff --git a/src/test/java/org/traccar/handler/DistanceHandlerTest.java b/src/test/java/org/traccar/handler/DistanceHandlerTest.java index a18b14edd..7d2f1e2e3 100644 --- a/src/test/java/org/traccar/handler/DistanceHandlerTest.java +++ b/src/test/java/org/traccar/handler/DistanceHandlerTest.java @@ -1,11 +1,11 @@ package org.traccar.handler; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.config.Config; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; public class DistanceHandlerTest { diff --git a/src/test/java/org/traccar/handler/FilterHandlerTest.java b/src/test/java/org/traccar/handler/FilterHandlerTest.java index a1102da88..9cb4a3bf2 100644 --- a/src/test/java/org/traccar/handler/FilterHandlerTest.java +++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java @@ -1,7 +1,7 @@ package org.traccar.handler; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -11,8 +11,8 @@ import org.traccar.session.cache.CacheManager; import java.util.Date; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; @@ -23,7 +23,7 @@ public class FilterHandlerTest extends BaseTest { private FilterHandler passingHandler; private FilterHandler filteringHandler; - @Before + @BeforeEach public void passingHandler() { var config = mock(Config.class); when(config.getBoolean(Keys.FILTER_ENABLE)).thenReturn(true); @@ -32,7 +32,7 @@ public class FilterHandlerTest extends BaseTest { passingHandler = new FilterHandler(config, cacheManager, null); } - @Before + @BeforeEach public void filteringHandler() { var config = mock(Config.class); when(config.getBoolean(Keys.FILTER_ENABLE)).thenReturn(true); diff --git a/src/test/java/org/traccar/handler/MotionHandlerTest.java b/src/test/java/org/traccar/handler/MotionHandlerTest.java index 93fd16206..2a7af23ba 100644 --- a/src/test/java/org/traccar/handler/MotionHandlerTest.java +++ b/src/test/java/org/traccar/handler/MotionHandlerTest.java @@ -1,10 +1,10 @@ package org.traccar.handler; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.model.Position; import org.traccar.reports.common.TripsConfig; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java index 550a93da3..66dc55c85 100644 --- a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java @@ -1,6 +1,6 @@ package org.traccar.handler.events; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.config.Config; import org.traccar.model.Event; @@ -9,8 +9,8 @@ import org.traccar.session.cache.CacheManager; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; public class AlertEventHandlerTest extends BaseTest { diff --git a/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java index 4997a0e0f..bc24e42f5 100644 --- a/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java @@ -1,14 +1,14 @@ package org.traccar.handler.events; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.model.Event; import org.traccar.model.Position; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class CommandResultEventHandlerTest extends BaseTest { diff --git a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java index 84898bea0..972932df4 100644 --- a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java @@ -1,6 +1,6 @@ package org.traccar.handler.events; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.model.Event; import org.traccar.model.Position; @@ -8,7 +8,7 @@ import org.traccar.session.cache.CacheManager; import java.util.Map; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.mock; public class IgnitionEventHandlerTest extends BaseTest { diff --git a/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java index aa2d0bbe3..5320be926 100644 --- a/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java @@ -1,6 +1,6 @@ package org.traccar.handler.events; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.model.Maintenance; import org.traccar.model.Position; @@ -9,7 +9,7 @@ import org.traccar.session.cache.CacheManager; import java.util.Arrays; import java.util.Date; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.ArgumentMatchers.eq; diff --git a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java index b77676dc8..f2d858656 100644 --- a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java @@ -1,6 +1,6 @@ package org.traccar.handler.events; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.model.Event; import org.traccar.model.Position; @@ -13,8 +13,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class MotionEventHandlerTest extends BaseTest { diff --git a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java index ee18ee052..25e9bd265 100644 --- a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java @@ -1,6 +1,6 @@ package org.traccar.handler.events; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.model.Event; import org.traccar.model.Position; @@ -12,9 +12,9 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; public class OverspeedEventHandlerTest extends BaseTest { diff --git a/src/test/java/org/traccar/helper/BcdUtilTest.java b/src/test/java/org/traccar/helper/BcdUtilTest.java index 86a32f725..440cd90d4 100644 --- a/src/test/java/org/traccar/helper/BcdUtilTest.java +++ b/src/test/java/org/traccar/helper/BcdUtilTest.java @@ -1,9 +1,9 @@ package org.traccar.helper; import io.netty.buffer.Unpooled; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class BcdUtilTest { diff --git a/src/test/java/org/traccar/helper/BitBufferTest.java b/src/test/java/org/traccar/helper/BitBufferTest.java index c2abad36d..3b3521213 100644 --- a/src/test/java/org/traccar/helper/BitBufferTest.java +++ b/src/test/java/org/traccar/helper/BitBufferTest.java @@ -1,8 +1,8 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class BitBufferTest { diff --git a/src/test/java/org/traccar/helper/BitUtilTest.java b/src/test/java/org/traccar/helper/BitUtilTest.java index 90431bf55..803c327bc 100644 --- a/src/test/java/org/traccar/helper/BitUtilTest.java +++ b/src/test/java/org/traccar/helper/BitUtilTest.java @@ -1,10 +1,10 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class BitUtilTest { diff --git a/src/test/java/org/traccar/helper/BufferUtilTest.java b/src/test/java/org/traccar/helper/BufferUtilTest.java index 0196cef9d..707e419ec 100644 --- a/src/test/java/org/traccar/helper/BufferUtilTest.java +++ b/src/test/java/org/traccar/helper/BufferUtilTest.java @@ -2,11 +2,11 @@ package org.traccar.helper; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.nio.charset.StandardCharsets; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class BufferUtilTest { diff --git a/src/test/java/org/traccar/helper/ChecksumTest.java b/src/test/java/org/traccar/helper/ChecksumTest.java index 248f4dcae..51f62aba0 100644 --- a/src/test/java/org/traccar/helper/ChecksumTest.java +++ b/src/test/java/org/traccar/helper/ChecksumTest.java @@ -2,12 +2,12 @@ package org.traccar.helper; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ChecksumTest { diff --git a/src/test/java/org/traccar/helper/DateBuilderTest.java b/src/test/java/org/traccar/helper/DateBuilderTest.java index b6323cc1d..35797a3ef 100644 --- a/src/test/java/org/traccar/helper/DateBuilderTest.java +++ b/src/test/java/org/traccar/helper/DateBuilderTest.java @@ -1,13 +1,13 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class DateBuilderTest { diff --git a/src/test/java/org/traccar/helper/DateUtilTest.java b/src/test/java/org/traccar/helper/DateUtilTest.java index ec42e71ae..b5a4b1eab 100644 --- a/src/test/java/org/traccar/helper/DateUtilTest.java +++ b/src/test/java/org/traccar/helper/DateUtilTest.java @@ -1,13 +1,13 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class DateUtilTest { diff --git a/src/test/java/org/traccar/helper/DistanceCalculatorTest.java b/src/test/java/org/traccar/helper/DistanceCalculatorTest.java index a7457b6c4..676fda5ea 100644 --- a/src/test/java/org/traccar/helper/DistanceCalculatorTest.java +++ b/src/test/java/org/traccar/helper/DistanceCalculatorTest.java @@ -1,8 +1,8 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class DistanceCalculatorTest { diff --git a/src/test/java/org/traccar/helper/LogTest.java b/src/test/java/org/traccar/helper/LogTest.java index ef33c32ba..a264896b5 100644 --- a/src/test/java/org/traccar/helper/LogTest.java +++ b/src/test/java/org/traccar/helper/LogTest.java @@ -1,8 +1,8 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LogTest { diff --git a/src/test/java/org/traccar/helper/ObdDecoderTest.java b/src/test/java/org/traccar/helper/ObdDecoderTest.java index d5071bd51..2233ab5b3 100644 --- a/src/test/java/org/traccar/helper/ObdDecoderTest.java +++ b/src/test/java/org/traccar/helper/ObdDecoderTest.java @@ -1,8 +1,8 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ObdDecoderTest { diff --git a/src/test/java/org/traccar/helper/PatternBuilderTest.java b/src/test/java/org/traccar/helper/PatternBuilderTest.java index 4c76bc463..a8657a2e7 100644 --- a/src/test/java/org/traccar/helper/PatternBuilderTest.java +++ b/src/test/java/org/traccar/helper/PatternBuilderTest.java @@ -1,8 +1,8 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PatternBuilderTest { diff --git a/src/test/java/org/traccar/helper/PatternUtilTest.java b/src/test/java/org/traccar/helper/PatternUtilTest.java index 77660078a..ff8efe773 100644 --- a/src/test/java/org/traccar/helper/PatternUtilTest.java +++ b/src/test/java/org/traccar/helper/PatternUtilTest.java @@ -1,13 +1,13 @@ package org.traccar.helper; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PatternUtilTest { - @Ignore + @Disabled @Test public void testCheckPattern() { diff --git a/src/test/java/org/traccar/helper/ServletHelperTest.java b/src/test/java/org/traccar/helper/ServletHelperTest.java index 55b96a41a..3a645bc36 100644 --- a/src/test/java/org/traccar/helper/ServletHelperTest.java +++ b/src/test/java/org/traccar/helper/ServletHelperTest.java @@ -1,10 +1,10 @@ package org.traccar.helper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import javax.servlet.http.HttpServletRequest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/src/test/java/org/traccar/notification/NotificiationMailTest.java b/src/test/java/org/traccar/notification/NotificiationMailTest.java index b82bec02e..41124140c 100644 --- a/src/test/java/org/traccar/notification/NotificiationMailTest.java +++ b/src/test/java/org/traccar/notification/NotificiationMailTest.java @@ -1,7 +1,7 @@ package org.traccar.notification; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import javax.mail.Message; import javax.mail.Session; @@ -25,7 +25,7 @@ public class NotificiationMailTest { private static final int PORT = 25; - @Ignore + @Disabled @Test public void test() throws Exception { diff --git a/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java index 02d42447e..bd50e1d14 100644 --- a/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AdmFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java index 810d53bf7..f09a42ba8 100644 --- a/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AdmProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java index 79f37c4e4..26f59015d 100644 --- a/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java @@ -16,11 +16,11 @@ */ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class AdmProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java index 36ea3d361..b322bbbc7 100644 --- a/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AisProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java index 585e02c02..84108160a 100644 --- a/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AlematicsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java index 5e0923e9c..aec26c0c1 100644 --- a/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AnytrekProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java index 369c13115..6aef8409b 100644 --- a/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ApelProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java index b055221f2..316e897a7 100644 --- a/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class AplicomFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java index 4b25830f8..b4b5da0ce 100644 --- a/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AplicomProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java index e821c9dba..d0dd368e7 100644 --- a/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AppelloProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java index 38c5d3b6d..fa9cc9851 100644 --- a/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AquilaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java index fd65ce585..9f567c87b 100644 --- a/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Ardi01ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java index b07dff150..e3a2658a8 100644 --- a/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ArknavProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java index 9686c694b..c81ef1684 100644 --- a/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ArknavX8ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java index 515f7f7b2..42e1ab477 100644 --- a/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java index f96da5203..e38e63755 100644 --- a/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ArnaviBinaryProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java index 92ca5d2b0..4997e535d 100644 --- a/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ArnaviFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java index e27367119..ed9fd0cfe 100644 --- a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ArnaviTextProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java index 2d8798dff..3dabcac5d 100644 --- a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AstraProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java b/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java index 773a8f7f5..c83a5fd4e 100644 --- a/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class At2000FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java index 8c32289f1..718542e97 100644 --- a/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assume.assumeTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; public class At2000ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java index 958814e53..7b2334919 100644 --- a/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AtrackFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java index b6b09fc25..dfdd3e579 100644 --- a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AtrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java index 368f7ed4c..d2ef74c02 100644 --- a/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AuroProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java index 30152e94c..f46fe6a3c 100644 --- a/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AustinNbProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java index 8e17d5673..f0c9c17bd 100644 --- a/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; diff --git a/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java index 7f837451c..be4b38a14 100644 --- a/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AutoGradeProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java index 51bbd0d8c..3b2f2c9b7 100644 --- a/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class AutoTrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java index 7f41d6b47..7d44e1b15 100644 --- a/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java index 1da432cea..ada32f8ee 100644 --- a/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; diff --git a/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java index ea3b38e7d..84b09e7b7 100644 --- a/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class B2316ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java b/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java index e5a442f2f..f25daca76 100644 --- a/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class BceFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java index 1d980b7e5..fdfb721c5 100644 --- a/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java @@ -1,13 +1,13 @@ package org.traccar.protocol; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; public class BceProtocolDecoderTest extends ProtocolTest { - @Ignore + @Disabled @Test public void testDecodeFail() throws Exception { diff --git a/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java index bfaa3ccd8..93c05fad6 100644 --- a/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java index 2fb93f2a9..7ec070615 100644 --- a/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class BlackKiteProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java index 1de542e24..33496fada 100644 --- a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java index 0a19eb3b0..d2af8282a 100644 --- a/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class BoxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java index ae4c47229..fd3561d18 100644 --- a/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class BstplProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java index 28876075d..0dc6529e1 100644 --- a/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class C2stekProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java index 1a8431f23..932facaee 100644 --- a/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class CalAmpProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java index d12d4aa9f..e5791c706 100644 --- a/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class CarTrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java index 71137cacf..d5e60e69c 100644 --- a/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class CarscopProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java index 1add623b7..e9cbac5ce 100644 --- a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java index 9b3a285da..e3e59b7e7 100644 --- a/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java index 4022d688b..dd8b812fa 100644 --- a/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class CautelaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java b/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java index c266dd1f4..aae9b434d 100644 --- a/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class CellocatorFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java index 27cad39a3..01dd9f4cb 100644 --- a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java index bb5d4979d..4d5c8cfe4 100644 --- a/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java @@ -1,13 +1,13 @@ package org.traccar.protocol; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; public class CellocatorProtocolEncoderTest extends ProtocolTest { - @Ignore + @Disabled @Test public void testEncode() throws Exception { diff --git a/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java index 835ab5fe5..df5141e44 100644 --- a/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class CguardProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java index 0c1fc1f5d..1f99e02e7 100644 --- a/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; diff --git a/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java index 6da9856c8..0b97ed9c8 100644 --- a/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java index 6ac2ae01d..659c5aa9c 100644 --- a/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ContinentalProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java index f95bfb54d..6e3ce2481 100644 --- a/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class CradlepointProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java index c63775858..6219b3da4 100644 --- a/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DingtekFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java index 7e5f68e05..3131ee1df 100644 --- a/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DingtekProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java index 3faccd7ea..a9b80664c 100644 --- a/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DishaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java index 99760546f..c2449ea91 100644 --- a/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DmtHttpProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java index 9c14a1ebe..6919f8ed8 100644 --- a/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DmtProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java index b9e3da67d..b24f30965 100644 --- a/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DolphinProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java index 7e3ec0706..b0c90ef7c 100644 --- a/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Dsf22FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java index 2e52b950d..dbf6f782c 100644 --- a/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Dsf22ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java b/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java index f74a40d13..495e20e8e 100644 --- a/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DualcamFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java index a61f20c13..de70e2b63 100644 --- a/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DualcamProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java index 1cdd82664..05b2757ad 100644 --- a/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class DwayProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java index ef319449e..bcd9aea45 100644 --- a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EasyTrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java index 1e1934435..a2a720263 100644 --- a/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class EasyTrackProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java index ec1467c09..6e2c41a7f 100644 --- a/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java index 380888843..300a1c5b6 100644 --- a/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java index dde71d1e7..af5e77116 100644 --- a/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EgtsFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java index 0f5a40605..aa0d666b1 100644 --- a/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EgtsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java index 2d2a211c3..c53d65ceb 100644 --- a/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EnforaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java index 0134e8052..5f1d152f6 100644 --- a/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EnnfuProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java index 50db6c743..68a3ee9e3 100644 --- a/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EnvotechProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java index 2d9b19b70..4cccff878 100644 --- a/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EsealProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java index 3ea8de5d6..e87a56b67 100644 --- a/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class EsealProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java b/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java index f808cd4a8..830ee4df0 100644 --- a/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class EskyFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java index 678007f5c..feec3ebfb 100644 --- a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java index 36a26bbe3..ccd7d4d20 100644 --- a/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ExtremTracProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java index 417c49de5..de320778a 100644 --- a/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FifotrackFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java index ec08b432c..518eada52 100644 --- a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java index c3352f510..643c9202d 100644 --- a/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class FifotrackProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java index c794c9094..47a6eab87 100644 --- a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FlespiProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java index ffb8eb3a9..bd54b4be0 100644 --- a/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FlexApiProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java index ed44fc62e..b0b0910c6 100644 --- a/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FlexCommProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java index 6b289396d..3bff46df0 100644 --- a/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FlexibleReportProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java index 6e5ebf4cf..2e0274d11 100644 --- a/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; diff --git a/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java index 8e62c878e..7918243e6 100644 --- a/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FoxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java index 1163b4e04..f8cdb8934 100644 --- a/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FreedomProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java index a7ce042e5..dae3815ac 100644 --- a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FreematicsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java b/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java index a101ef45d..40d8e619e 100644 --- a/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FutureWayFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java index e529d5c90..e8af86d66 100644 --- a/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class FutureWayProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java index c8b4e35fe..059fc21df 100644 --- a/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class G1rusProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java index a5aba3513..256517460 100644 --- a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class GalileoFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java index 7addc8e75..2611832ff 100644 --- a/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GalileoProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java index 29fe4cc94..af640f3d4 100644 --- a/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java index bfb33de22..6f1bd88db 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class GatorProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java index 67a730f97..0f90c9b07 100644 --- a/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GenxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java index 31ae1d5e8..d835f2f27 100644 --- a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Gl100ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java index cad70c35b..680b3b77c 100644 --- a/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Gl200BinaryProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java index 51816222d..6fd3f0aaa 100644 --- a/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Gl200FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 5696353c4..515c14921 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java index e244a835d..7391fea28 100644 --- a/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GlobalSatProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java index 9001c4bf3..dc00cad44 100644 --- a/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class GlobalSatProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java index 730d4bb60..8d4210e9d 100644 --- a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GlobalstarProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java index 592c2de91..78722fa17 100644 --- a/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GnxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java index 71ffbb587..ad944d73a 100644 --- a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java index a6e3f2d69..aea6e7592 100644 --- a/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java index cb75b4035..332423645 100644 --- a/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Gps056FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java index ac3738644..29cc6b09f 100644 --- a/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Gps056ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java index cf5786d75..c11a5b0d9 100644 --- a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java index f6cbe6d17..3df64039c 100644 --- a/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Gps103ProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java index a1f81b329..000163ba8 100644 --- a/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GpsGateProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java index bc7910779..8a5cb434b 100644 --- a/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; diff --git a/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java index d1326515f..73da69d96 100644 --- a/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GpsmtaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java b/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java index a61e708f7..9d6c189f6 100644 --- a/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class GranitFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java index d2e181e09..ff45bd99c 100644 --- a/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class GranitProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java index ce2768448..c382b3262 100644 --- a/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Gs100ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java index 25f59a948..100ef340a 100644 --- a/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Gt02ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java index a9d011277..c74427f90 100644 --- a/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Gt06FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 697908a4c..3b4cb158e 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java index 13463ea39..80b50df3a 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java index 48c4306d6..4d7e8699e 100644 --- a/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Gt30ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java b/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java index c61c0f0c9..dc6eec84d 100644 --- a/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class H02FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java index e68f0814c..a63488960 100644 --- a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java index 1be9421bb..2fc7af958 100644 --- a/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; @@ -11,7 +11,7 @@ import java.time.LocalTime; import java.time.ZoneOffset; import java.util.Date; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class H02ProtocolEncoderTest extends ProtocolTest { @@ -19,7 +19,7 @@ public class H02ProtocolEncoderTest extends ProtocolTest { private final Date time = Date.from( LocalDateTime.of(LocalDate.now(), LocalTime.of(1, 2, 3)).atZone(ZoneOffset.systemDefault()).toInstant()); - @Before + @BeforeEach public void before() throws Exception { encoder = inject(new H02ProtocolEncoder(null)); } diff --git a/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java index 9d26d56c3..5ad5693be 100644 --- a/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class HaicomProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java index 8fe4d2c8b..ac814a5f4 100644 --- a/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class HomtecsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java index ed7b0534b..8d57bf787 100644 --- a/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class HoopoProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java index 991e0b36d..26494f2b9 100644 --- a/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class HuaShengFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java index 7002d7e88..ee6c3fa7f 100644 --- a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java index 6b902fb46..a76beac20 100644 --- a/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class HuabaoFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 04c3a8cd3..95abc43a7 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java index 6f9c8250a..87cc2b12e 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java @@ -1,13 +1,13 @@ package org.traccar.protocol; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; public class HuabaoProtocolEncoderTest extends ProtocolTest { - @Ignore + @Disabled @Test public void testEncode() throws Exception { diff --git a/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java index 5503ab02c..e932ff7e9 100644 --- a/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class HunterProProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java index 1bd52ce89..da4e25fda 100644 --- a/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class IdplProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java index b6e12aef5..8de96a890 100644 --- a/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class IntellitracProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java index c668084a1..c4f01fde4 100644 --- a/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java @@ -2,7 +2,7 @@ package org.traccar.protocol; import io.netty.handler.codec.mqtt.MqttMessageBuilders; import io.netty.handler.codec.mqtt.MqttQoS; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class IotmProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java index 26f28916c..ebdb6fd0f 100644 --- a/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ItsFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java index dd8d3a0d9..86b438c7c 100644 --- a/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java index 195fc4258..b9bda0c0a 100644 --- a/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ItsProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java index b08dff4e7..45655898e 100644 --- a/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Ivt401ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java index b275e6d01..6b60e19cc 100644 --- a/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class JidoProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java index a1b0acac5..c8e29d2ec 100644 --- a/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class JpKorjarProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java b/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java index 1bc5d8480..f40bcd720 100644 --- a/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class JsonFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java index 895a0b07b..2dce2309d 100644 --- a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Jt600FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java index fc52e32e3..32213fda1 100644 --- a/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Jt600ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java index fdd73b9ce..5c8c260b7 100644 --- a/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Jt600ProtocolEncoderTest extends ProtocolTest { Jt600ProtocolEncoder encoder = new Jt600ProtocolEncoder(null); diff --git a/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java index a705d8082..1425bc066 100755 --- a/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class KenjiProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java index 155493bea..b7e868077 100644 --- a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class KhdProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java index 468083f35..1ee652cd9 100644 --- a/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java b/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java index 084ae0498..a9e0a26fe 100644 --- a/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class L100FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java index 56281cda0..105e1f3f5 100644 --- a/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class L100ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java index 45544241f..a8afb8573 100644 --- a/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class LacakProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java index aacf9abc8..4df486d56 100644 --- a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class LaipacProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java index ea31bc99d..dcff59f0c 100644 --- a/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class LeafSpyProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java index 674738c82..0ac1ea92f 100644 --- a/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class M2cProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java index 0d812ebfc..c4db6945d 100644 --- a/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class M2mProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java index be0fe502e..237ef45b5 100644 --- a/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class MaestroProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java index a77043b9d..560c7967b 100644 --- a/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ManPowerProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java index 0c74d4772..add137114 100644 --- a/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Mavlink2ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java index 854564cd2..996a4c98a 100644 --- a/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class MegastekFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java index 964c59927..227fb20e0 100644 --- a/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java index 379cf28f9..2647c49db 100644 --- a/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class MeiligaoFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java index 4c6eae847..8074636a3 100644 --- a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java index 1f2e5f7e3..f62a9f722 100644 --- a/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java index a55935ed2..f86b676a6 100644 --- a/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MeitrackFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index ec45933a3..1697fc920 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java index cc8847db2..ac9854b8e 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MeitrackProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java index 5e36abe5b..3f790d2f9 100644 --- a/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java index 275672554..d14c020d4 100644 --- a/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class MilesmateProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java index a8f1be855..d955d8e50 100644 --- a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java index 502f8e8bf..f61779a38 100644 --- a/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MiniFinderProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java index 0809996f6..2013fa820 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Minifinder2ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java index fea74db7a..b6cc2ed77 100644 --- a/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java index 82781550e..8e51271b6 100644 --- a/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class MoovboxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java index f3ebb8e5c..9de24d87f 100644 --- a/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class MotorProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java index 8a5e228c7..86a72cc2d 100644 --- a/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class MtxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java index 68a68c9e8..c1f02f0ae 100644 --- a/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class MxtProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java index 8eda687cc..5b5865855 100644 --- a/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NavigilProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java index 29327f7e1..8678a55ba 100644 --- a/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NavisFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java index 960ed1442..56f5a4c9f 100644 --- a/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NavisProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java index d15d01cc0..8f25c2127 100644 --- a/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NavisetFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java index d7643b50c..7722560ca 100644 --- a/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NavisetProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java index 360f92447..1509472a7 100644 --- a/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NavtelecomFrameDecoderTest extends ProtocolTest { @@ -24,7 +24,7 @@ public class NavtelecomFrameDecoderTest extends ProtocolTest { } - @Ignore + @Disabled @Test public void testDecodeFull() throws Exception { diff --git a/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java index 301a72b2a..d715ea596 100644 --- a/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NavtelecomProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java index c63c19a29..67e88cb5a 100644 --- a/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NdtpV6ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java index 4e9e55f62..841315895 100644 --- a/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NeosProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java index 239d892f8..d208b10c5 100644 --- a/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NetProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java index 03aaa49aa..8fa74abd0 100644 --- a/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NiotProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java index 3f1ec7aee..3a3461d43 100644 --- a/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NoranProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java index d1b28525c..ddcc02418 100644 --- a/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java index dd5e1d9b9..d4dcdcc60 100644 --- a/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class NvsFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java index 61d050679..0c8b41e4a 100644 --- a/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NvsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java index b3bd9aca7..9dcfe8a78 100644 --- a/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class NyitechProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java index 8272fe41e..53d910ddb 100644 --- a/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ObdDongleProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java index 6015f1d18..4541bf9c0 100644 --- a/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OigoProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java index 19c96ed9a..d3bd4fde4 100644 --- a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OkoProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java b/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java index 8e8d9b1cf..1a4365f3c 100644 --- a/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OmnicommFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java index 5b3b08194..9f509718a 100644 --- a/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OmnicommProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java index 5494301d8..e2db193d1 100644 --- a/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OpenGtsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java index 408053496..21ccfa56d 100644 --- a/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OrbcommProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java index f5b98574c..5308568fd 100644 --- a/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OrionProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java index 3b8a94613..c779e4c6e 100644 --- a/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OsmAndProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java index edb7d1aad..7347da0fb 100644 --- a/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OutsafeProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java index 03332e7fe..ba0eaec01 100644 --- a/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class OwnTracksProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java index bde464162..4ae0e6d54 100644 --- a/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; import io.netty.buffer.Unpooled; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PacificTrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java index 97020343f..afd131e95 100644 --- a/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PathAwayProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java index 0dd00462d..cb101fa5f 100644 --- a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PiligrimProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java index 8b15d70a6..59f624eaa 100644 --- a/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java index 8bf109d11..67bac7823 100644 --- a/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PolteProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java index 8bc16d373..c5d57aa25 100644 --- a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PortmanProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java index b4c334a0c..41e78cf6c 100644 --- a/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PortmanProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java index 5dbde7846..ca4d5de07 100644 --- a/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PretraceProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java index d3218d4a8..da18441f5 100644 --- a/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PretraceProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java index 8c2081641..6988f2f72 100644 --- a/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PricolProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java index 9129a3079..ff205ce35 100644 --- a/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ProgressProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java b/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java index 172d85df6..45960d783 100644 --- a/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PstFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java b/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java index bc458c398..bbc17dbea 100644 --- a/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java +++ b/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java @@ -2,7 +2,7 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PstFrameEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java index 880caf727..1fe7d7da4 100644 --- a/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PstProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java index 6c3ff71b6..b6530d815 100644 --- a/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java index a5f5d7e77..234aff97b 100644 --- a/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Pt215ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java index f7b278139..b731b82ad 100644 --- a/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Pt3000ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java index 854c789b8..f007dbb18 100644 --- a/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Pt502FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java index f310b2227..2fc9c8073 100644 --- a/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java index c97093e26..98fe147b2 100644 --- a/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Pt502ProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java index b198ac28e..5dca8a0c6 100644 --- a/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Pt60ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java index a363022f0..4fbc4938e 100644 --- a/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class R12wProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java index ff40c19a3..c8ed2269d 100644 --- a/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RaceDynamicsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java index b5a2555b1..81fdcfd0b 100644 --- a/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RadarProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java index 3da671dbf..b951ef7b4 100644 --- a/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RaveonProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java index 5bdfd6816..defc5e8f9 100644 --- a/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RecodaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java index eb591a5f6..d27979d1b 100644 --- a/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RetranslatorProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java index df19f01c6..8073c5459 100644 --- a/src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RfTrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java index 0d7eeb0df..7fb5f6335 100644 --- a/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RitiProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java index e4b30538c..f54cf8fcc 100644 --- a/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RoboTrackFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java index db1617c9e..5a83ae1b6 100644 --- a/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RoboTrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java index b301507fb..13095765b 100644 --- a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java index 89d4a02cc..f214ce5f8 100644 --- a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class RuptelaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java index 0c4fc6767..bb6c098f0 100644 --- a/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java index 2b7f40c82..cebae3ef6 100644 --- a/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class S168ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java index 15b1d0451..689de29b2 100644 --- a/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class SabertekFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java index 6aafa325f..b55681ffd 100644 --- a/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SabertekProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java index d0ae6fabf..5e1a24f3b 100644 --- a/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SanavProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java index 57398dd84..f01205155 100644 --- a/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SanulProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java index 0fe16377d..c58971d02 100644 --- a/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SatsolProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java index 66d5f5e69..cc6c17014 100644 --- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java index 0d7eb4f16..e599ff36d 100644 --- a/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SiwiProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java index e59e3c3f0..d2bf0f825 100644 --- a/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SkypatrolProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java index 258eb0fce..9bad24865 100644 --- a/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SmartSoleProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java index de025c18e..a8a9223c8 100644 --- a/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SmokeyProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java index 445628f6d..a18c7ee9b 100644 --- a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java index 03d0e97f0..70b645b8f 100644 --- a/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SpotProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java index 0a6ad0163..f06bb9aac 100644 --- a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java index 84c470970..6e2489bfe 100644 --- a/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class StarcomProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java index 072c19942..361e6e6f2 100644 --- a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java index f04d0cb67..c87e421f2 100644 --- a/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class StartekProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java index c618ac21c..dbdeee4d7 100644 --- a/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class StbProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java index 3ef4b1901..353fe4317 100644 --- a/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Stl060ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java index 6d0351a8e..0db6e756c 100644 --- a/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SuntechFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index 107c03d36..884f13350 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; @@ -209,7 +209,7 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { } - @Ignore + @Disabled @Test public void testDecodeCrash() throws Exception { diff --git a/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java index e96c9b62d..4fa209fb7 100755 --- a/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SupermateProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java index fb9053706..694a178f4 100644 --- a/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SviasProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java index 923b7abfb..6b473b38c 100644 --- a/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class SwiftechProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java index e04e473bb..7b9841d68 100644 --- a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java b/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java index 40d5bc9e9..1e39298fa 100644 --- a/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class T57FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java index 2e097562b..e0fd2e800 100644 --- a/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class T57ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java index 10d0aad59..246687149 100644 --- a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java index b2d7c57a2..4741f5c92 100644 --- a/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java index 36c9d9148..bc5901fb0 100644 --- a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java index b4617cb61..28a917096 100644 --- a/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TechTltProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java index 36c3b578b..1e1f8d431 100644 --- a/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TechtoCruzFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java index 459401469..b512f9968 100644 --- a/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TechtoCruzProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java index 98b2b80c4..fa6a490a4 100644 --- a/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TekFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java index 17910a8d6..9976b9bac 100644 --- a/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TekProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java index 9f36b3f96..8770e9451 100644 --- a/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TelemaxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java index dc6cc58c6..ba3808534 100644 --- a/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TelicFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java index 214bb06c7..44e63b8a6 100644 --- a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TelicProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java index adc768460..8d0cafcd9 100644 --- a/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TeltonikaFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java index ba64642f2..60b58f626 100644 --- a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TeltonikaProtocolDecoderTest extends ProtocolTest { @@ -158,7 +158,7 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest { } - @Ignore + @Disabled @Test public void testDecodeConnectionless() throws Exception { diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java index d7e1149aa..04e8afe0b 100644 --- a/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java index fc66f53bb..674db0ad5 100644 --- a/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TeraTrackProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java index 2085112ec..0271bf3a2 100644 --- a/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ThinkPowerProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java index 859dd4f89..73e40ce55 100644 --- a/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ThinkRaceProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java index 90431fa24..b9bc1dbc2 100644 --- a/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class ThurayaProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java index 3bcc9994a..2c495d09d 100644 --- a/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Tk102ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java index 87c3d9317..a3cfa24cf 100644 --- a/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java @@ -1,7 +1,7 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Tk103FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java index 8b3177136..9fc8b81b2 100644 --- a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java index 359e432c7..57ebbaec1 100644 --- a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Tk103ProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java index a6a9f836e..46dc031a3 100644 --- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java index d6d1b7275..547014752 100644 --- a/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TlvProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java index 9cdcb6169..fe9ac26f1 100644 --- a/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TmgFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java index 6d3c36005..12402e068 100644 --- a/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TmgProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java index b49345a42..67b04446e 100644 --- a/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TopflytechProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java index 5e7ec1136..763c4f2da 100644 --- a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java index a69f389ac..b6ba9b0eb 100644 --- a/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java index 175c32848..5eff60e51 100644 --- a/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TotemFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java index 1e432bd9e..949e69275 100644 --- a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java index 97a044b51..795f75842 100644 --- a/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TotemProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java index e4917c872..1323691c6 100644 --- a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Tr20ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java index 96ddf4175..636f2101a 100644 --- a/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Tr900ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java index 10603db1c..514ef2647 100644 --- a/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TrackboxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java index 7542b3456..55ccd2f0b 100644 --- a/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TrakMateProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java index cf997c237..8c88f0ebb 100644 --- a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TramigoFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java index 32bc05e23..dc0ca2b73 100644 --- a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TramigoProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java index 6dc28d89e..31cb5b36d 100644 --- a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TrvProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java index 3f5c60daa..e471671f8 100644 --- a/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Tt8850ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java index de6f3a6ff..d42a249e8 100644 --- a/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TytanProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java index 4a861fb06..4813021fd 100644 --- a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class TzoneProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java b/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java index 534287e0a..9b10328f6 100644 --- a/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class UlbotechFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java index 52f2520cc..5d2692a8a 100644 --- a/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class UlbotechProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java index 50e9321ce..0ee1516ba 100644 --- a/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java index 8d32eebb1..c99166374 100644 --- a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java index 40776278d..492f241e5 100644 --- a/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class UuxProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java index 105dc8339..d8e3f1f53 100644 --- a/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class V680ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java index 042b66cae..ff43a94ab 100644 --- a/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class VisiontekProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java index 25cc03781..ead1624d8 100644 --- a/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class VnetProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java index 7d039dc8f..a869e7dc1 100644 --- a/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Vt200FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java index 25ce5550a..c4533aa11 100644 --- a/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java index e381153a2..18baf75cb 100644 --- a/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java @@ -1,9 +1,9 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class VtfmsFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java index 4925d9769..8ca1b9df5 100644 --- a/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class VtfmsProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java index 42464c6fe..8b0486322 100644 --- a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class WatchFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java index 37fab7e40..855b9792c 100644 --- a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.database.MediaManager; import org.traccar.model.Position; diff --git a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java index c83c103c3..649c0016b 100644 --- a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java index 29a86e0ac..e67a798ff 100644 --- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class WialonProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java index 45c86ae1a..405fc340e 100644 --- a/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class WliFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java index e74b1df06..482c15da0 100644 --- a/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class WliProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java index a1cbfe737..f1f65cb2c 100644 --- a/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class WondexFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java index 72ba8e163..8f86263c4 100644 --- a/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class WondexProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java index f482871dd..2e1a45c8c 100644 --- a/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class WondexProtocolEncoderTest extends ProtocolTest { @Test diff --git a/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java index b901820fe..ba40486a6 100644 --- a/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class WristbandProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java index 34437862c..9e909f1ca 100644 --- a/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Xexun2FrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java b/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java index d327930b5..27e894705 100644 --- a/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java @@ -2,7 +2,7 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Xexun2FrameEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java index 48ba1a691..b373c8283 100644 --- a/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Xexun2ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java index 483bc85fa..62d511c0b 100644 --- a/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; diff --git a/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java b/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java index 9bc39fc97..82287f6ad 100644 --- a/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class XexunFrameDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java index f7599b4c3..7331827f0 100644 --- a/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class XexunProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java index db9c829aa..8f912d9e2 100644 --- a/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class XirgoProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java index 76e2f960d..2efedf51a 100644 --- a/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class XirgoProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java index 8ed175a74..fae163a56 100644 --- a/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Xrb28ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java index a66efecc2..eaa29a833 100644 --- a/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java @@ -1,10 +1,10 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Xrb28ProtocolEncoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java index 007af984e..43c1f0676 100644 --- a/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Xt013ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java index 35cb3c3fa..881ff1ee9 100644 --- a/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class Xt2400ProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java index 81afe53a3..a5a2a11d1 100644 --- a/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java @@ -1,6 +1,6 @@ package org.traccar.protocol; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class YwtProtocolDecoderTest extends ProtocolTest { diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index aa166dc25..09e5b3e27 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -1,8 +1,8 @@ package org.traccar.reports; import org.apache.velocity.app.VelocityEngine; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.api.security.PermissionsService; import org.traccar.config.Config; @@ -26,10 +26,10 @@ import java.util.Iterator; import java.util.List; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -38,7 +38,7 @@ public class ReportUtilsTest extends BaseTest { private Storage storage; - @Before + @BeforeEach public void init() throws StorageException { storage = mock(Storage.class); when(storage.getObject(any(), any())).thenReturn(mock(Device.class)); diff --git a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java index 202983f1e..5ea13bf9c 100644 --- a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java +++ b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java @@ -1,19 +1,19 @@ package org.traccar.speedlimit; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class OverpassSpeedLimitProviderTest { private final Client client = ClientBuilder.newClient(); - @Ignore + @Disabled @Test public void testOverpass() throws Exception { SpeedLimitProvider provider = new OverpassSpeedLimitProvider(client, "http://8.8.8.8/api/interpreter"); diff --git a/src/test/java/org/traccar/web/WebServerTest.java b/src/test/java/org/traccar/web/WebServerTest.java index ba4124e44..694dab18a 100644 --- a/src/test/java/org/traccar/web/WebServerTest.java +++ b/src/test/java/org/traccar/web/WebServerTest.java @@ -1,6 +1,6 @@ package org.traccar.web; -import org.junit.Test; +import org.junit.jupiter.api.Test; import javax.naming.Context; import javax.naming.InitialContext; -- cgit v1.2.3 From 3feb9c15e32c619cd94e7a58b79cd54001751a45 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 6 Mar 2023 11:07:28 -0800 Subject: Enable unit tests --- build.gradle | 8 +++++++- src/test/java/org/traccar/ProtocolTest.java | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 17728e0ce..a9f9f07cd 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,7 @@ ext { jacksonVersion = "2.13.3" // same version as jersey-media-json-jackson dependency protobufVersion = "3.21.12" jxlsVersion = "2.12.0" + junitVersion = "5.9.2" } protobuf { @@ -85,10 +86,15 @@ dependencies { implementation "com.hivemq:hivemq-mqtt-client:1.3.0" implementation "redis.clients:jedis:4.3.1" implementation "com.google.firebase:firebase-admin:9.1.1" - testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.2" + testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testImplementation "org.mockito:mockito-core:4.+" } +test { + useJUnitPlatform() +} + task copyDependencies(type: Copy) { into "$projectDir/target/lib" from configurations.runtimeClasspath diff --git a/src/test/java/org/traccar/ProtocolTest.java b/src/test/java/org/traccar/ProtocolTest.java index ce005e93f..3b04b5e02 100644 --- a/src/test/java/org/traccar/ProtocolTest.java +++ b/src/test/java/org/traccar/ProtocolTest.java @@ -179,7 +179,7 @@ public class ProtocolTest extends BaseTest { if (expected.getFixTime() != null) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - assertEquals("time", dateFormat.format(expected.getFixTime()), dateFormat.format(position.getFixTime())); + assertEquals(dateFormat.format(expected.getFixTime()), dateFormat.format(position.getFixTime()), "time"); } assertEquals(expected.getValid(), position.getValid(), "valid"); assertEquals(expected.getLatitude(), position.getLatitude(), 0.00001, "latitude"); -- cgit v1.2.3 From 785933bc74b2530ed36b4d5fae364284e28cf5d9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 6 Mar 2023 11:32:57 -0800 Subject: Upgrade mockito version --- build.gradle | 2 +- src/test/java/org/traccar/BaseTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a9f9f07cd..b27403861 100644 --- a/build.gradle +++ b/build.gradle @@ -88,7 +88,7 @@ dependencies { implementation "com.google.firebase:firebase-admin:9.1.1" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:4.+" + testImplementation "org.mockito:mockito-core:5.1.1" } test { diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java index c784150dd..2ace781f3 100644 --- a/src/test/java/org/traccar/BaseTest.java +++ b/src/test/java/org/traccar/BaseTest.java @@ -32,7 +32,7 @@ public class BaseTest { decoder.setCacheManager(cacheManager); var connectionManager = mock(ConnectionManager.class); var uniqueIdsProvided = new HashSet(); - when(connectionManager.getDeviceSession(any(), any(), any(), any())).thenAnswer(invocation -> { + when(connectionManager.getDeviceSession(any(), any(), any(), any(String[].class))).thenAnswer(invocation -> { var mock = new DeviceSession(1L, "", mock(Protocol.class), mock(Channel.class), mock(SocketAddress.class)); if (uniqueIdsProvided.isEmpty()) { if (invocation.getArguments().length > 3) { -- cgit v1.2.3 From 2749e520c9ea1ba778c120739e2b67a9fe5e119c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 9 Mar 2023 09:26:32 -0800 Subject: Add JT705A gyro axis --- .../java/org/traccar/protocol/HuabaoProtocolDecoder.java | 16 ++++++++++++++++ .../org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index d6deafe17..d3336b60c 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -753,6 +753,22 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_STATUS, status); + while (buf.readableBytes() > 2) { + int id = buf.readUnsignedByte(); + int length = buf.readUnsignedByte(); + switch (id) { + case 0x02: + position.setAltitude(buf.readShort()); + break; + case 0x0C: + position.set("gyro", ByteBufUtil.hexDump(buf.readSlice(6))); + break; + default: + buf.skipBytes(length); + break; + } + } + return position; } diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 95abc43a7..9590f7732 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyAttribute(decoder, binary( + "7e55019c3b8571110003399a07032310302029538631031015370500001a0c000000265700440001233703080000001001020202000a0a04028f000af401040c06ff98ffa8007e707e"), + "gyro", "ff98ffa8007e"); + verifyPosition(decoder, binary( "7e0900001f4f07788ef87d000cf0230223150215010203013800000c000b029dc58c04b99b60230223171822507e")); -- cgit v1.2.3 From f4d10160d9513eb190169d0ab335c3d99c6d4e31 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 10 Mar 2023 07:34:15 -0800 Subject: Decode bark count --- src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java | 4 ++++ .../java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 0b08badb8..aa43a6054 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -277,6 +277,10 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { i += 1; } break; + case 0x37: + buf.readUnsignedIntLE(); // timestamp + position.set("barkCount", BitUtil.to(buf.readUnsignedIntLE(), 31)); + break; case 0x40: buf.readUnsignedIntLE(); // timestamp int heartRate = buf.readUnsignedByte(); diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java index 2013fa820..693a11fc5 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java @@ -10,6 +10,10 @@ public class Minifinder2ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Minifinder2ProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "ab101c00d6f61e000110013836333932313033393939363038300937efd201640c000000"), + "barkCount", 12L); + verifyAttribute(decoder, binary( "ab102600080f1400011001383633393231303339393833343736092429b347633003a96409020000008027b34763"), "bark", true); -- cgit v1.2.3 From 4fc5d0b58b3667ee1bb81515deef6440225af76b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 10 Mar 2023 15:18:18 -0800 Subject: Clean up MQTT forwarder --- src/main/java/org/traccar/forward/EventForwarderMqtt.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/forward/EventForwarderMqtt.java b/src/main/java/org/traccar/forward/EventForwarderMqtt.java index dc95cb4e2..7f4e29384 100644 --- a/src/main/java/org/traccar/forward/EventForwarderMqtt.java +++ b/src/main/java/org/traccar/forward/EventForwarderMqtt.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -21,8 +21,6 @@ import com.hivemq.client.mqtt.datatypes.MqttQos; import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient; import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5SimpleAuth; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -32,7 +30,6 @@ import java.util.UUID; public class EventForwarderMqtt implements EventForwarder { - private static final Logger LOGGER = LoggerFactory.getLogger(EventForwarderMqtt.class); private final Mqtt5AsyncClient client; private final ObjectMapper objectMapper; @@ -63,7 +60,7 @@ public class EventForwarderMqtt implements EventForwarder { String host = url.getHost(); int port = url.getPort(); client = Mqtt5Client.builder() - .identifier("traccar-" + UUID.randomUUID().toString()) + .identifier("traccar-" + UUID.randomUUID()) .serverHost(host) .serverPort(port) .simpleAuth(simpleAuth) -- cgit v1.2.3 From 08612944b879861c37b34688e0e9ef2d4a8c11a2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 12 Mar 2023 11:03:25 -0700 Subject: Implement memory storage --- src/main/java/org/traccar/MainModule.java | 12 +- src/main/java/org/traccar/config/Keys.java | 7 ++ .../java/org/traccar/storage/MemoryStorage.java | 126 ++++++++++++++++++++- 3 files changed, 141 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index ae42d6712..663747de1 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -84,6 +84,7 @@ import org.traccar.sms.SnsSmsClient; import org.traccar.speedlimit.OverpassSpeedLimitProvider; import org.traccar.speedlimit.SpeedLimitProvider; import org.traccar.storage.DatabaseStorage; +import org.traccar.storage.MemoryStorage; import org.traccar.storage.Storage; import org.traccar.web.WebServer; @@ -108,10 +109,19 @@ public class MainModule extends AbstractModule { protected void configure() { bindConstant().annotatedWith(Names.named("configFile")).to(configFile); bind(Config.class).asEagerSingleton(); - bind(Storage.class).to(DatabaseStorage.class).in(Scopes.SINGLETON); bind(Timer.class).to(HashedWheelTimer.class).in(Scopes.SINGLETON); } + @Singleton + @Provides + public static Storage provideStorage(Injector injector, Config config) { + if (config.getBoolean(Keys.DATABASE_MEMORY)) { + return injector.getInstance(MemoryStorage.class); + } else { + return injector.getInstance(DatabaseStorage.class); + } + } + @Singleton @Provides public static ObjectMapper provideObjectMapper(Config config) { diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6aa41f85b..1b4b3a5b4 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -385,6 +385,13 @@ public final class Keys { List.of(KeyType.CONFIG), 25.0); + /** + * Enable in-memory database instead of an SQL database. + */ + public static final ConfigKey DATABASE_MEMORY = new BooleanConfigKey( + "database.memory", + List.of(KeyType.CONFIG)); + /** * Path to the database driver JAR file. Traccar includes drivers for MySQL, PostgreSQL and H2 databases. If you use * one of those, you don't need to specify this parameter. diff --git a/src/main/java/org/traccar/storage/MemoryStorage.java b/src/main/java/org/traccar/storage/MemoryStorage.java index f19897ff8..9b5db1209 100644 --- a/src/main/java/org/traccar/storage/MemoryStorage.java +++ b/src/main/java/org/traccar/storage/MemoryStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -18,35 +18,155 @@ package org.traccar.storage; import org.traccar.model.BaseModel; import org.traccar.model.Pair; import org.traccar.model.Permission; +import org.traccar.model.Server; +import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; +import java.beans.Introspector; +import java.lang.reflect.Method; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; public class MemoryStorage extends Storage { + private final Map, Map> objects = new HashMap<>(); private final Map, Class>, Set>> permissions = new HashMap<>(); + private final AtomicLong increment = new AtomicLong(); + + public MemoryStorage() { + Server server = new Server(); + server.setId(1); + server.setRegistration(true); + objects.put(Server.class, Map.of(server.getId(), server)); + } + @Override public List getObjects(Class clazz, Request request) { - return null; + return objects.computeIfAbsent(clazz, key -> new HashMap<>()).values().stream() + .filter(object -> checkCondition(request.getCondition(), object)) + .map(object -> (T) object) + .collect(Collectors.toList()); + } + + private boolean checkCondition(Condition genericCondition, Object object) { + if (genericCondition == null) { + return true; + } + + if (genericCondition instanceof Condition.Compare) { + + var condition = (Condition.Compare) genericCondition; + Object value = retrieveValue(object, condition.getVariable()); + int result = ((Comparable) value).compareTo(condition.getValue()); + switch (condition.getOperator()) { + case "<": + return result < 0; + case "<=": + return result <= 0; + case ">": + return result > 0; + case ">=": + return result >= 0; + case "=": + return result == 0; + default: + throw new RuntimeException("Unsupported comparison condition"); + } + + } else if (genericCondition instanceof Condition.Between) { + + var condition = (Condition.Between) genericCondition; + Object fromValue = retrieveValue(object, condition.getFromVariable()); + int fromResult = ((Comparable) fromValue).compareTo(condition.getFromValue()); + Object toValue = retrieveValue(object, condition.getToVariable()); + int toResult = ((Comparable) toValue).compareTo(condition.getToValue()); + return fromResult >= 0 && toResult <= 0; + + } else if (genericCondition instanceof Condition.Binary) { + + var condition = (Condition.Binary) genericCondition; + if (condition.getOperator().equals("AND")) { + return checkCondition(condition.getFirst(), object) && checkCondition(condition.getSecond(), object); + } else if (condition.getOperator().equals("OR")) { + return checkCondition(condition.getFirst(), object) || checkCondition(condition.getSecond(), object); + } + + } else if (genericCondition instanceof Condition.Permission) { + + var condition = (Condition.Permission) genericCondition; + long id = (Long) retrieveValue(object, "id"); + return getPermissionsSet(condition.getOwnerClass(), condition.getPropertyClass()).stream() + .anyMatch(pair -> { + if (condition.getOwnerId() > 0) { + return pair.getFirst() == condition.getOwnerId() && pair.getSecond() == id; + } else { + return pair.getFirst() == id && pair.getSecond() == condition.getPropertyId(); + } + }); + + } else if (genericCondition instanceof Condition.LatestPositions) { + + return false; + + } + + return false; + } + + private Object retrieveValue(Object object, String key) { + try { + Method method = object.getClass().getMethod( + "get" + Character.toUpperCase(key.charAt(0)) + key.substring(1)); + return method.invoke(object); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } } @Override public long addObject(T entity, Request request) { - return 0; + long id = increment.incrementAndGet(); + objects.computeIfAbsent(entity.getClass(), key -> new HashMap<>()).put(id, entity); + return id; } @Override public void updateObject(T entity, Request request) { + Set columns = new HashSet<>(request.getColumns().getColumns(entity.getClass(), "get")); + Collection items; + if (request.getCondition() != null) { + long id = (Long) ((Condition.Equals) request.getCondition()).getValue(); + items = List.of(objects.computeIfAbsent(entity.getClass(), key -> new HashMap<>()).get(id)); + } else { + items = objects.computeIfAbsent(entity.getClass(), key -> new HashMap<>()).values(); + } + for (Method setter : entity.getClass().getMethods()) { + if (setter.getName().startsWith("set") && setter.getParameterCount() == 1 + && columns.contains(Introspector.decapitalize(setter.getName()))) { + try { + Method getter = entity.getClass().getMethod(setter.getName().replaceFirst("set", "get")); + Object value = getter.invoke(entity); + for (Object object : items) { + setter.invoke(object, value); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + } } @Override public void removeObject(Class clazz, Request request) { + long id = (Long) ((Condition.Equals) request.getCondition()).getValue(); + objects.computeIfAbsent(clazz, key -> new HashMap<>()).remove(id); } private Set> getPermissionsSet(Class ownerClass, Class propertyClass) { -- cgit v1.2.3 From 016c107821a6df94a6f71659f9f067334fbc75fd Mon Sep 17 00:00:00 2001 From: bernamaxim Date: Mon, 13 Mar 2023 11:53:43 +0700 Subject: RegisterUnknown filter with regex #5023 update PR #5044 --- setup/default.xml | 2 ++ src/main/java/org/traccar/config/Keys.java | 7 +++++++ src/main/java/org/traccar/session/ConnectionManager.java | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/setup/default.xml b/setup/default.xml index 75acf25a1..f7f1af15b 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -39,6 +39,8 @@ true true + \w{3,15} + ./schema/changelog-master.xml 5001 diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 1b4b3a5b4..7896f0dc4 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -494,6 +494,13 @@ public final class Keys { "database.registerUnknown.defaultGroupId", List.of(KeyType.CONFIG)); + /** + * Automatically register unknown devices with regex filter. + */ + public static final ConfigKey DATABASE_REGISTER_UNKNOWN_REGEX = new StringConfigKey( + "database.registerUnknown.regex", + List.of(KeyType.CONFIG)); + /** * Store empty messages as positions. For example, heartbeats. */ diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 37a42d827..e6f5d00cf 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -123,7 +123,9 @@ public class ConnectionManager implements BroadcastInterface { Device device = deviceLookupService.lookup(uniqueIds); if (device == null && config.getBoolean(Keys.DATABASE_REGISTER_UNKNOWN)) { - device = addUnknownDevice(uniqueIds[0]); + if (uniqueIds[0].matches(config.getString(Keys.DATABASE_REGISTER_UNKNOWN_REGEX))) { + device = addUnknownDevice(uniqueIds[0]); + } } if (device != null) { -- cgit v1.2.3 From 1a3b85ca28e938ac055be20851893f6d5a470a25 Mon Sep 17 00:00:00 2001 From: Bernard Date: Mon, 13 Mar 2023 22:34:46 +0700 Subject: Update default.xml --- setup/default.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup/default.xml b/setup/default.xml index f7f1af15b..75acf25a1 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -39,8 +39,6 @@ true true - \w{3,15} - ./schema/changelog-master.xml 5001 -- cgit v1.2.3 From 0ed96dc475883bf2d56e6308089d6891ca521b18 Mon Sep 17 00:00:00 2001 From: Bernard Date: Mon, 13 Mar 2023 22:36:21 +0700 Subject: Update Keys.java --- src/main/java/org/traccar/config/Keys.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 7896f0dc4..3c7346833 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -499,7 +499,7 @@ public final class Keys { */ public static final ConfigKey DATABASE_REGISTER_UNKNOWN_REGEX = new StringConfigKey( "database.registerUnknown.regex", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), "\w{3,15}"); /** * Store empty messages as positions. For example, heartbeats. -- cgit v1.2.3 From fc0b4234d1d0d668769819b40c476a51beab0c1d Mon Sep 17 00:00:00 2001 From: Bernard Date: Mon, 13 Mar 2023 23:26:53 +0700 Subject: Update Keys.java --- src/main/java/org/traccar/config/Keys.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 3c7346833..491c724aa 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -499,7 +499,7 @@ public final class Keys { */ public static final ConfigKey DATABASE_REGISTER_UNKNOWN_REGEX = new StringConfigKey( "database.registerUnknown.regex", - List.of(KeyType.CONFIG), "\w{3,15}"); + List.of(KeyType.CONFIG), "\\w{3,15}"); /** * Store empty messages as positions. For example, heartbeats. -- cgit v1.2.3 From 5c0962c257d51bef081d25405c972dd54035a0b2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 14 Mar 2023 09:43:34 -0700 Subject: Add bark stopped flag --- src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index aa43a6054..37e86e243 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -279,7 +279,11 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { break; case 0x37: buf.readUnsignedIntLE(); // timestamp - position.set("barkCount", BitUtil.to(buf.readUnsignedIntLE(), 31)); + long barking = buf.readUnsignedIntLE(); + if (BitUtil.check(barking, 31)) { + position.set("barkStop", true); + } + position.set("barkCount", BitUtil.to(barking, 31)); break; case 0x40: buf.readUnsignedIntLE(); // timestamp -- cgit v1.2.3 From d4816aae87600334fe798e8b50b9f11df6f0b293 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 16 Mar 2023 09:55:19 -0700 Subject: Option for system only emails --- src/main/java/org/traccar/api/resource/PasswordResource.java | 2 +- src/main/java/org/traccar/config/Keys.java | 7 +++++++ src/main/java/org/traccar/mail/LogMailManager.java | 10 ++++++---- src/main/java/org/traccar/mail/MailManager.java | 8 +++++--- src/main/java/org/traccar/mail/SmtpMailManager.java | 10 ++++++---- src/main/java/org/traccar/notificators/NotificatorMail.java | 2 +- src/main/java/org/traccar/reports/common/ReportMailer.java | 2 +- 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 2d87a8665..67c9cee97 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -63,7 +63,7 @@ public class PasswordResource extends BaseResource { if (user != null) { var velocityContext = textTemplateFormatter.prepareContext(permissionsService.getServer(), user); var fullMessage = textTemplateFormatter.formatMessage(velocityContext, "passwordReset", "full"); - mailManager.sendMessage(user, fullMessage.getSubject(), fullMessage.getBody()); + mailManager.sendMessage(user, true, fullMessage.getSubject(), fullMessage.getBody()); } return Response.ok().build(); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 491c724aa..cb1ee63e1 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -835,6 +835,13 @@ public final class Keys { "mail.debug", List.of(KeyType.CONFIG)); + /** + * Restrict global SMTP configuration to system messages only (e.g. password reset). + */ + public static final ConfigKey MAIL_SMTP_SYSTEM_ONLY = new BooleanConfigKey( + "mail.smtp.systemOnly", + List.of(KeyType.CONFIG)); + /** * Force SMTP settings from the config file and ignore user attributes. */ diff --git a/src/main/java/org/traccar/mail/LogMailManager.java b/src/main/java/org/traccar/mail/LogMailManager.java index 4af68809c..5c7572b0c 100644 --- a/src/main/java/org/traccar/mail/LogMailManager.java +++ b/src/main/java/org/traccar/mail/LogMailManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -32,12 +32,14 @@ public class LogMailManager implements MailManager { } @Override - public void sendMessage(User user, String subject, String body) throws MessagingException { - sendMessage(user, subject, body, null); + public void sendMessage( + User user, boolean system, String subject, String body) throws MessagingException { + sendMessage(user, system, subject, body, null); } @Override - public void sendMessage(User user, String subject, String body, MimeBodyPart attachment) throws MessagingException { + public void sendMessage( + User user, boolean system, String subject, String body, MimeBodyPart attachment) throws MessagingException { LOGGER.info( "Email sent\nTo: {}\nSubject: {}\nAttachment: {}\nBody:\n{}", user.getEmail(), subject, attachment != null ? attachment.getFileName() : null, body); diff --git a/src/main/java/org/traccar/mail/MailManager.java b/src/main/java/org/traccar/mail/MailManager.java index 69efbed32..3547fd37e 100644 --- a/src/main/java/org/traccar/mail/MailManager.java +++ b/src/main/java/org/traccar/mail/MailManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -24,8 +24,10 @@ public interface MailManager { boolean getEmailEnabled(); - void sendMessage(User user, String subject, String body) throws MessagingException; + void sendMessage( + User user, boolean system, String subject, String body) throws MessagingException; - void sendMessage(User user, String subject, String body, MimeBodyPart attachment) throws MessagingException; + void sendMessage( + User user, boolean system, String subject, String body, MimeBodyPart attachment) throws MessagingException; } diff --git a/src/main/java/org/traccar/mail/SmtpMailManager.java b/src/main/java/org/traccar/mail/SmtpMailManager.java index 4a0b7048f..8d1afbd3e 100644 --- a/src/main/java/org/traccar/mail/SmtpMailManager.java +++ b/src/main/java/org/traccar/mail/SmtpMailManager.java @@ -93,19 +93,21 @@ public final class SmtpMailManager implements MailManager { return config.hasKey(Keys.MAIL_SMTP_HOST); } + @Override public void sendMessage( - User user, String subject, String body) throws MessagingException { - sendMessage(user, subject, body, null); + User user, boolean system, String subject, String body) throws MessagingException { + sendMessage(user, system, subject, body, null); } + @Override public void sendMessage( - User user, String subject, String body, MimeBodyPart attachment) throws MessagingException { + User user, boolean system, String subject, String body, MimeBodyPart attachment) throws MessagingException { Properties properties = null; if (!config.getBoolean(Keys.MAIL_SMTP_IGNORE_USER_CONFIG)) { properties = getProperties(new PropertiesProvider(user)); } - if (properties == null) { + if (properties == null && (system || !config.getBoolean(Keys.MAIL_SMTP_SYSTEM_ONLY))) { properties = getProperties(new PropertiesProvider(config)); } if (properties == null) { diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java index 7f755f170..8818a5a75 100644 --- a/src/main/java/org/traccar/notificators/NotificatorMail.java +++ b/src/main/java/org/traccar/notificators/NotificatorMail.java @@ -44,7 +44,7 @@ public class NotificatorMail implements Notificator { public void send(Notification notification, User user, Event event, Position position) throws MessageException { try { var fullMessage = notificationFormatter.formatMessage(user, event, position, "full"); - mailManager.sendMessage(user, fullMessage.getSubject(), fullMessage.getBody()); + mailManager.sendMessage(user, false, fullMessage.getSubject(), fullMessage.getBody()); } catch (MessagingException e) { throw new MessageException(e); } diff --git a/src/main/java/org/traccar/reports/common/ReportMailer.java b/src/main/java/org/traccar/reports/common/ReportMailer.java index 221b35ae1..3ce41934f 100644 --- a/src/main/java/org/traccar/reports/common/ReportMailer.java +++ b/src/main/java/org/traccar/reports/common/ReportMailer.java @@ -55,7 +55,7 @@ public class ReportMailer { stream.toByteArray(), "application/octet-stream"))); User user = permissionsService.getUser(userId); - mailManager.sendMessage(user, "Report", "The report is in the attachment.", attachment); + mailManager.sendMessage(user, false, "Report", "The report is in the attachment.", attachment); } catch (StorageException | IOException | MessagingException e) { LOGGER.warn("Email report failed", e); } -- cgit v1.2.3 From 765f1bdbe7418a8808faf578e2dcf1adc6094bc9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Mar 2023 17:57:25 -0700 Subject: Fix device id --- src/main/java/org/traccar/protocol/T55ProtocolDecoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java index 4db76f601..b18359b3f 100644 --- a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java @@ -353,6 +353,7 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { } Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); getLastLocation(position, null); -- cgit v1.2.3 From ffe4c83b226308932e8a1c1388104c9070a3184b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Mar 2023 21:53:15 -0700 Subject: Support HuaSheng commands --- .../org/traccar/protocol/HuaShengProtocol.java | 9 ++- .../traccar/protocol/HuaShengProtocolDecoder.java | 4 +- .../traccar/protocol/HuaShengProtocolEncoder.java | 71 ++++++++++++++++++++++ .../protocol/HuaShengProtocolEncoderTest.java | 23 +++++++ 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java create mode 100644 src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocol.java b/src/main/java/org/traccar/protocol/HuaShengProtocol.java index b1b61e977..4a0ebe5d7 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocol.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -19,6 +19,7 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.model.Command; import javax.inject.Inject; @@ -26,10 +27,16 @@ public class HuaShengProtocol extends BaseProtocol { @Inject public HuaShengProtocol(Config config) { + setSupportedDataCommands( + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM, + Command.TYPE_SET_SPEED_LIMIT); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new HuaShengFrameDecoder()); + pipeline.addLast(new HuaShengProtocolEncoder(HuaShengProtocol.this)); pipeline.addLast(new HuaShengProtocolDecoder(HuaShengProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 371691d82..993e36978 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -48,6 +48,8 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_UPFAULT_RSP = 0xFF13; public static final int MSG_HSO_REQ = 0x0002; public static final int MSG_HSO_RSP = 0x0003; + public static final int MSG_SET_REQ = 0xAA04; + public static final int MSG_SET_RSP = 0xFF05; private void sendResponse(Channel channel, int type, int index, ByteBuf content) { if (channel != null) { diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java new file mode 100644 index 000000000..636196ec4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java @@ -0,0 +1,71 @@ +/* + * 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.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.model.Command; + +public class HuaShengProtocolEncoder extends BaseProtocolEncoder { + + public HuaShengProtocolEncoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf encodeContent(ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + buf.writeByte(0xC0); + buf.writeShort(0x0000); // flag and version + buf.writeShort(12 + content.readableBytes()); + buf.writeShort(HuaShengProtocolDecoder.MSG_SET_REQ); + buf.writeShort(0); // checksum + buf.writeInt(1); // index + buf.writeBytes(content); + content.release(); + buf.writeByte(0xC0); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + ByteBuf content = Unpooled.buffer(0); + switch (command.getType()) { + case Command.TYPE_POSITION_PERIODIC: + content.writeShort(0x0002); + content.writeShort(6); // length + content.writeShort(command.getInteger(Command.KEY_FREQUENCY)); + return encodeContent(content); + case Command.TYPE_ALARM_ARM: + case Command.TYPE_ALARM_DISARM: + content.writeShort(0x0001); + content.writeShort(5); // length + content.writeByte(command.getType().equals(Command.TYPE_ALARM_ARM) ? 1 : 0); + case Command.TYPE_SET_SPEED_LIMIT: + content.writeShort(0x0004); + content.writeShort(6); // length + content.writeShort(command.getInteger(Command.KEY_DATA)); + return encodeContent(content); + default: + return null; + } + } + +} diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java new file mode 100644 index 000000000..b44f6e89c --- /dev/null +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class HuaShengProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + var encoder = inject(new HuaShengProtocolEncoder(null)); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_PERIODIC); + command.set(Command.KEY_FREQUENCY, 60); + + verifyCommand(encoder, command, binary("c000000012aa0400000000000100020006003cc0")); + + } + +} -- cgit v1.2.3 From 2d20fbd1740f302af5a1e7522e728c0939a323a0 Mon Sep 17 00:00:00 2001 From: wkhaksar <31837615+wkhaksar@users.noreply.github.com> Date: Tue, 21 Mar 2023 15:16:49 +0000 Subject: changed-session-retreival-permission-to-manager --- src/main/java/org/traccar/api/resource/SessionResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 7025d5fa7..ff84c135f 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -123,7 +123,7 @@ public class SessionResource extends BaseResource { @Path("{id}") @GET public User get(@PathParam("id") long userId) throws StorageException { - permissionsService.checkAdmin(getUserId()); + permissionsService.checkUser(getUserId(), userId); User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Equals("id", userId))); request.getSession().setAttribute(USER_ID_KEY, user.getId()); -- cgit v1.2.3 From 2a0b2dee5eecd55f86c51fe2a25f7ac7484d6bde Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Mar 2023 13:40:50 -0700 Subject: Response after position processed --- src/main/java/org/traccar/BasePipelineFactory.java | 16 ++- .../java/org/traccar/ExtendedObjectDecoder.java | 12 +- src/main/java/org/traccar/MainEventHandler.java | 3 + src/main/java/org/traccar/config/Keys.java | 7 ++ .../traccar/handler/AcknowledgementHandler.java | 121 +++++++++++++++++++++ .../java/org/traccar/handler/FilterHandler.java | 23 ++-- .../org/traccar/handler/FilterHandlerTest.java | 18 +-- 7 files changed, 177 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/traccar/handler/AcknowledgementHandler.java diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index b184da45c..70f999c72 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -25,6 +25,7 @@ import io.netty.channel.ChannelPipeline; import io.netty.handler.timeout.IdleStateHandler; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.handler.AcknowledgementHandler; import org.traccar.handler.ComputedAttributesHandler; import org.traccar.handler.CopyAttributesHandler; import org.traccar.handler.DefaultDataHandler; @@ -60,15 +61,19 @@ public abstract class BasePipelineFactory extends ChannelInitializer { private final Injector injector; private final TrackerConnector connector; private final String protocol; - private int timeout; + private final boolean instantAcknowledgement; + private final int timeout; public BasePipelineFactory(TrackerConnector connector, Config config, String protocol) { this.injector = Main.getInjector(); this.connector = connector; this.protocol = protocol; - timeout = config.getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol)); + instantAcknowledgement = config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT); + int timeout = config.getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol)); if (timeout == 0) { - timeout = config.getInteger(Keys.SERVER_TIMEOUT); + this.timeout = config.getInteger(Keys.SERVER_TIMEOUT); + } else { + this.timeout = timeout; } } @@ -112,6 +117,9 @@ public abstract class BasePipelineFactory extends ChannelInitializer { pipeline.addLast(new OpenChannelHandler(connector)); pipeline.addLast(new NetworkMessageHandler()); pipeline.addLast(new StandardLoggingHandler(protocol)); + if (!instantAcknowledgement) { + pipeline.addLast(new AcknowledgementHandler()); + } addProtocolHandlers(handler -> { if (handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder) { diff --git a/src/main/java/org/traccar/ExtendedObjectDecoder.java b/src/main/java/org/traccar/ExtendedObjectDecoder.java index f79a36c85..805f98cb7 100644 --- a/src/main/java/org/traccar/ExtendedObjectDecoder.java +++ b/src/main/java/org/traccar/ExtendedObjectDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -23,6 +23,7 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.ReferenceCountUtil; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.handler.AcknowledgementHandler; import org.traccar.helper.DataConverter; import org.traccar.model.Position; @@ -30,6 +31,7 @@ import javax.inject.Inject; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.Collection; +import java.util.List; public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter { @@ -68,6 +70,7 @@ public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { NetworkMessage networkMessage = (NetworkMessage) msg; Object originalMessage = networkMessage.getMessage(); + ctx.writeAndFlush(new AcknowledgementHandler.EventReceived()); try { Object decodedMessage = decode(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage); onMessageEvent(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage, decodedMessage); @@ -76,14 +79,19 @@ public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter } if (decodedMessage != null) { if (decodedMessage instanceof Collection) { - for (Object o : (Collection) decodedMessage) { + var collection = (Collection) decodedMessage; + ctx.writeAndFlush(new AcknowledgementHandler.EventDecoded(collection)); + for (Object o : collection) { saveOriginal(o, originalMessage); ctx.fireChannelRead(o); } } else { + ctx.writeAndFlush(new AcknowledgementHandler.EventDecoded(List.of(decodedMessage))); saveOriginal(decodedMessage, originalMessage); ctx.fireChannelRead(decodedMessage); } + } else { + ctx.writeAndFlush(new AcknowledgementHandler.EventDecoded(List.of())); } } finally { ReferenceCountUtil.release(originalMessage); diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index 877f03ae7..658ff6d6d 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.StatisticsManager; +import org.traccar.handler.AcknowledgementHandler; import org.traccar.helper.DateUtil; import org.traccar.helper.NetworkUtil; import org.traccar.helper.model.PositionUtil; @@ -145,6 +146,8 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { LOGGER.info(builder.toString()); statisticsManager.registerMessageStored(position.getDeviceId(), position.getProtocol()); + + ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); } } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index cb1ee63e1..c207efb1e 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -292,6 +292,13 @@ public final class Keys { "server.timeout", List.of(KeyType.CONFIG)); + /** + * Send device responses immediately before writing it in the database. + */ + public static final ConfigKey SERVER_INSTANT_ACKNOWLEDGEMENT = new BooleanConfigKey( + "server.instantAcknowledgement", + List.of(KeyType.CONFIG)); + /** * Address for uploading aggregated anonymous usage statistics. Uploaded information is the same you can see on the * statistics screen in the web app. It does not include any sensitive (e.g. locations). diff --git a/src/main/java/org/traccar/handler/AcknowledgementHandler.java b/src/main/java/org/traccar/handler/AcknowledgementHandler.java new file mode 100644 index 000000000..c3f6038de --- /dev/null +++ b/src/main/java/org/traccar/handler/AcknowledgementHandler.java @@ -0,0 +1,121 @@ +/* + * 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.handler; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class AcknowledgementHandler extends ChannelOutboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AcknowledgementHandler.class); + + public interface Event { + } + + public static class EventReceived implements Event { + } + + public static class EventDecoded implements Event { + private final Collection objects; + + public EventDecoded(Collection objects) { + this.objects = objects; + } + + public Collection getObjects() { + return objects; + } + } + + public static class EventHandled implements Event { + private final Object object; + + public EventHandled(Object object) { + this.object = object; + } + + public Object getObject() { + return object; + } + } + + private static class Entry { + private final Object message; + private final ChannelPromise promise; + + private Entry(Object message, ChannelPromise promise) { + this.message = message; + this.promise = promise; + } + + public Object getMessage() { + return message; + } + + public ChannelPromise getPromise() { + return promise; + } + } + + private List queue; + private final Set waiting = new HashSet<>(); + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + List output = new LinkedList<>(); + synchronized (this) { + if (msg instanceof Event) { + if (msg instanceof EventReceived) { + LOGGER.debug("Event received"); + if (queue == null) { + queue = new LinkedList<>(); + } + } else if (msg instanceof EventDecoded) { + EventDecoded event = (EventDecoded) msg; + LOGGER.debug("Event decoded {}", event.getObjects().size()); + waiting.addAll(event.getObjects()); + } else if (msg instanceof EventHandled) { + EventHandled event = (EventHandled) msg; + LOGGER.debug("Event handled"); + waiting.remove(event.getObject()); + } + if (!(msg instanceof EventReceived) && waiting.isEmpty()) { + output.addAll(queue); + queue = null; + } + } else if (queue != null) { + LOGGER.debug("Message queued"); + queue.add(new Entry(msg, promise)); + } else { + LOGGER.debug("Message sent"); + output.add(new Entry(msg, promise)); + } + } + for (Entry entry : output) { + ctx.write(entry.getMessage(), entry.getPromise()); + } + } + +} diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 994276bb6..1d1c27b7a 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 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. @@ -16,9 +16,10 @@ package org.traccar.handler; import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.traccar.BaseDataHandler; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; @@ -39,7 +40,7 @@ import java.util.Date; @Singleton @ChannelHandler.Sharable -public class FilterHandler extends BaseDataHandler { +public class FilterHandler extends ChannelInboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class); @@ -177,7 +178,7 @@ public class FilterHandler extends BaseDataHandler { return false; } - private boolean filter(Position position) { + protected boolean filter(Position position) { StringBuilder filterType = new StringBuilder(); @@ -243,11 +244,17 @@ public class FilterHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { - if (enabled && filter(position)) { - return null; + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof Position) { + Position position = (Position) msg; + if (enabled && filter(position)) { + ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); + } else { + ctx.fireChannelRead(position); + } + } else { + super.channelRead(ctx, msg); } - return position; } } diff --git a/src/test/java/org/traccar/handler/FilterHandlerTest.java b/src/test/java/org/traccar/handler/FilterHandlerTest.java index 9cb4a3bf2..26281e351 100644 --- a/src/test/java/org/traccar/handler/FilterHandlerTest.java +++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java @@ -11,8 +11,8 @@ import org.traccar.session.cache.CacheManager; import java.util.Date; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; @@ -71,18 +71,18 @@ public class FilterHandlerTest extends BaseTest { Position position = createPosition(new Date(), true, 10); - assertNotNull(filteringHandler.handlePosition(position)); - assertNotNull(passingHandler.handlePosition(position)); + assertFalse(filteringHandler.filter(position)); + assertFalse(passingHandler.filter(position)); position = createPosition(new Date(Long.MAX_VALUE), true, 10); - assertNull(filteringHandler.handlePosition(position)); - assertNotNull(passingHandler.handlePosition(position)); + assertTrue(filteringHandler.filter(position)); + assertFalse(passingHandler.filter(position)); position = createPosition(new Date(), false, 10); - assertNull(filteringHandler.handlePosition(position)); - assertNotNull(passingHandler.handlePosition(position)); + assertTrue(filteringHandler.filter(position)); + assertFalse(passingHandler.filter(position)); } @@ -92,7 +92,7 @@ public class FilterHandlerTest extends BaseTest { Position position = createPosition(new Date(), true, 0); position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - assertNotNull(filteringHandler.handlePosition(position)); + assertFalse(filteringHandler.filter(position)); } -- cgit v1.2.3 From a07e078645418720ad4bbe4ce352cae607c42175 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Mar 2023 13:44:14 -0700 Subject: Fix lint check --- src/main/java/org/traccar/handler/AcknowledgementHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/AcknowledgementHandler.java b/src/main/java/org/traccar/handler/AcknowledgementHandler.java index c3f6038de..4c1085998 100644 --- a/src/main/java/org/traccar/handler/AcknowledgementHandler.java +++ b/src/main/java/org/traccar/handler/AcknowledgementHandler.java @@ -61,7 +61,7 @@ public class AcknowledgementHandler extends ChannelOutboundHandlerAdapter { } } - private static class Entry { + private static final class Entry { private final Object message; private final ChannelPromise promise; -- cgit v1.2.3 From 5f56a56d77216fa46a63eabbcef67d59d4d7c817 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Mar 2023 21:46:12 -0700 Subject: Support BS50 battery info --- .../org/traccar/protocol/Tk103ProtocolDecoder.java | 64 +++++++++++++++++++++- .../traccar/protocol/Tk103ProtocolDecoderTest.java | 4 ++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java index b343c3b33..2b50e55c2 100644 --- a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -15,8 +15,11 @@ */ package org.traccar.protocol; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.DataConverter; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -448,6 +451,63 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeBms(Channel channel, SocketAddress remoteAddress, String sentence) { + String id = sentence.substring(1, 13); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + ByteBuf buf = Unpooled.wrappedBuffer( + DataConverter.parseHex(sentence.substring(1 + 12 + 4, sentence.length() - 1))); + + buf.readUnsignedByte(); + buf.readUnsignedByte(); + buf.readUnsignedByte(); // header + + int batteryCount = buf.readUnsignedByte(); + for (int i = 1; i <= 24; i++) { + int voltage = buf.readUnsignedShortLE(); + if (i <= batteryCount) { + position.set("battery" + i, voltage * 0.001); + } + } + + position.set(Position.KEY_CHARGE, buf.readUnsignedByte() == 0); + position.set("current", buf.readUnsignedShortLE() * 0.1); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set("batteryOverheat", buf.readUnsignedByte() > 0); + position.set("chargeProtection", buf.readUnsignedByte() > 0); + position.set("dischargeProtection", buf.readUnsignedByte() > 0); + buf.readUnsignedByte(); // drop line + buf.readUnsignedByte(); // balanced + position.set("cycles", buf.readUnsignedShortLE()); + position.set("faultAlarm", buf.readUnsignedByte()); + + buf.skipBytes(6); + + int temperatureCount = buf.readUnsignedByte(); + position.set("powerTemp", buf.readUnsignedByte() - 40); + position.set("equilibriumTemp", buf.readUnsignedByte() - 40); + for (int i = 1; i <= 7; i++) { + int temperature = buf.readUnsignedByte() - 40; + if (i <= temperatureCount) { + position.set("batteryTemp" + i, temperature); + } + } + + position.set("calibrationCapacity", buf.readUnsignedShortLE() * 0.01); + position.set("dischargeCapacity", buf.readUnsignedIntLE()); + + return position; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -477,6 +537,8 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { return decodeLbsWifi(channel, remoteAddress, sentence); } else if (sentence.contains("BV00")) { return decodeVin(channel, remoteAddress, sentence); + } else if (sentence.contains("BS50")) { + return decodeBms(channel, remoteAddress, sentence); } Parser parser = new Parser(PATTERN, sentence); diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java index 9fc8b81b2..1631ab051 100644 --- a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Tk103ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tk103ProtocolDecoder(null)); + verifyAttribute(decoder, text( + "(352602014867BS500064FF0EF10FF10FF00FF20FF30FF20FF20FF40FF20FF40FF40FF20FF30FF20F0000000000000000000000000000000000000000000000001663000000010004000000000000000002444444420000000000A00FA000000000000000200000000315E2000000)"), + "batteryTemp2", 26); + verifyAttributes(decoder, text( "(027046434858BZ00,{460,0,20949,58711}\n{460,0,20494,54003}\n{460,0,20951,19569}\n,01000000)")); -- cgit v1.2.3 From 2bb447924b834693f4d97585f1e5e9e822b62fe3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Mar 2023 07:57:06 -0700 Subject: Encoder bypass other events --- src/main/java/org/traccar/BaseProtocolEncoder.java | 45 +++++++++++----------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java index 9c3934184..96de3e3f0 100644 --- a/src/main/java/org/traccar/BaseProtocolEncoder.java +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -71,31 +71,30 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - NetworkMessage networkMessage = (NetworkMessage) msg; - - if (networkMessage.getMessage() instanceof Command) { - - Command command = (Command) networkMessage.getMessage(); - Object encodedCommand = encodeCommand(ctx.channel(), command); - - StringBuilder s = new StringBuilder(); - s.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); - s.append("id: ").append(getUniqueId(command.getDeviceId())).append(", "); - s.append("command type: ").append(command.getType()).append(" "); - if (encodedCommand != null) { - s.append("sent"); - } else { - s.append("not sent"); + if (msg instanceof NetworkMessage) { + NetworkMessage networkMessage = (NetworkMessage) msg; + if (networkMessage.getMessage() instanceof Command) { + + Command command = (Command) networkMessage.getMessage(); + Object encodedCommand = encodeCommand(ctx.channel(), command); + + StringBuilder s = new StringBuilder(); + s.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); + s.append("id: ").append(getUniqueId(command.getDeviceId())).append(", "); + s.append("command type: ").append(command.getType()).append(" "); + if (encodedCommand != null) { + s.append("sent"); + } else { + s.append("not sent"); + } + LOGGER.info(s.toString()); + + ctx.write(new NetworkMessage(encodedCommand, networkMessage.getRemoteAddress()), promise); + + return; } - LOGGER.info(s.toString()); - - ctx.write(new NetworkMessage(encodedCommand, networkMessage.getRemoteAddress()), promise); - - } else { - - super.write(ctx, msg, promise); - } + super.write(ctx, msg, promise); } protected Object encodeCommand(Channel channel, Command command) { -- cgit v1.2.3 From f8fb3f67bc0bc44f9da89c3dabbec7406751e3c6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Mar 2023 09:07:24 -0700 Subject: Decode TZone magnetic card --- .../org/traccar/protocol/TzoneProtocolDecoder.java | 37 ++++++++++++++-------- .../traccar/protocol/TzoneProtocolDecoderTest.java | 4 +++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java index 8e84a6781..ba9b41654 100644 --- a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java @@ -204,30 +204,39 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder { } - private void decodeTags(Position position, ByteBuf buf) { + private void decodeTags(Position position, ByteBuf buf, int hardware) { int blockLength = buf.readUnsignedShort(); int blockEnd = buf.readerIndex() + blockLength; if (blockLength > 0) { - buf.readUnsignedByte(); // tag type + int type = buf.readUnsignedByte(); - int count = buf.readUnsignedByte(); - int tagLength = buf.readUnsignedByte(); + if (hardware != 0x153 || type >= 2) { - for (int i = 1; i <= count; i++) { - int tagEnd = buf.readerIndex() + tagLength; + int count = buf.readUnsignedByte(); + int tagLength = buf.readUnsignedByte(); + + for (int i = 1; i <= count; i++) { + int tagEnd = buf.readerIndex() + tagLength; + + buf.readUnsignedByte(); // status + buf.readUnsignedShortLE(); // battery voltage - buf.readUnsignedByte(); // status - buf.readUnsignedShortLE(); // battery voltage + position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1); + + buf.readUnsignedByte(); // humidity + buf.readUnsignedByte(); // rssi + + buf.readerIndex(tagEnd); + } - position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1); + } else if (type == 1) { - buf.readUnsignedByte(); // humidity - buf.readUnsignedByte(); // rssi + position.set("driverLicense", buf.readCharSequence( + blockEnd - buf.readerIndex(), StandardCharsets.UTF_8).toString()); - buf.readerIndex(tagEnd); } } @@ -364,9 +373,9 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder { } - if (hardware == 0x406) { + if (hardware == 0x153 || hardware == 0x406) { - decodeTags(position, buf); + decodeTags(position, buf, hardware); } diff --git a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java index 4813021fd..8fdc8c23c 100644 --- a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java @@ -10,6 +10,10 @@ public class TzoneProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TzoneProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "545a00d424240153011300000863835029944118170316023b180016040485c73d2479187e170316023b1800000000060c000000000d1cc0406303019904aa00000000008a012520205e544f4e474c4f4d245049544f4f4e244d522e5e5e3f3b363030373634333132303130303134323234323d3139303631393538313032363d3f2b2020202020202020202020202032322020202020202020202020203120202020202020202020202030303234363238202031303730302020202020202020202020202020202020202020203f00030080000006e80e0d0a"), + "driverLicense", "% ^TONGLOM$PITOON$MR.^^?;6007643120100142242=190619581026=?+ 22 1 0024628 10700 ?"); + verifyAttributes(decoder, binary( "545a003724240407020200000180322000001610160b151019100000000c010a07320101088600007dca000baa102837016a0114025500000169e80d0a")); -- cgit v1.2.3 From ee3cbd4aba2e7df2ac2da4292caa87a63b171a87 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Mar 2023 19:21:07 -0700 Subject: Decode JT705A tilt --- .../java/org/traccar/protocol/HuabaoProtocolDecoder.java | 14 +++++++++++++- .../org/traccar/protocol/HuabaoProtocolDecoderTest.java | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index d3336b60c..22c39c2da 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -761,7 +761,19 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.setAltitude(buf.readShort()); break; case 0x0C: - position.set("gyro", ByteBufUtil.hexDump(buf.readSlice(6))); + int x = buf.readUnsignedShort(); + if (x > 0x8000) { + x -= 0x10000; + } + int y = buf.readUnsignedShort(); + if (y > 0x8000) { + y -= 0x10000; + } + int z = buf.readUnsignedShort(); + if (z > 0x8000) { + z -= 0x10000; + } + position.set("tilt", String.format("[%d,%d,%d]", x, y, z)); break; default: buf.skipBytes(length); diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 9590f7732..1737593e4 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -16,7 +16,7 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyAttribute(decoder, binary( "7e55019c3b8571110003399a07032310302029538631031015370500001a0c000000265700440001233703080000001001020202000a0a04028f000af401040c06ff98ffa8007e707e"), - "gyro", "ff98ffa8007e"); + "tilt", "[-104,-88,126]"); verifyPosition(decoder, binary( "7e0900001f4f07788ef87d000cf0230223150215010203013800000c000b029dc58c04b99b60230223171822507e")); -- cgit v1.2.3 From f73263da4800f86203e1aa425b0b7d3243d4b7c3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Mar 2023 09:17:25 -0700 Subject: Add JT808 power and battery --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 22c39c2da..ddc3192eb 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -329,6 +329,13 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x03: position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1); break; + case 0x56: + buf.readUnsignedByte(); // power level + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + break; + case 0x61: + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + break; case 0x80: position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); break; -- cgit v1.2.3 From 7c2f9e56ba5f699d22ec2939408357b5a220bacc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Mar 2023 09:38:30 -0700 Subject: Fix Wialon parameter decoding --- src/main/java/org/traccar/protocol/WialonProtocolDecoder.java | 3 ++- src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index ffa4472ef..4d1b34dba 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -63,8 +63,9 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { .number("(?:NA|(d+));") // outputs .expression("(?:NA|([^;]*));") // adc .expression("(?:NA|([^;]*));") // ibutton - .expression("(?:NA|(.*))") // params + .expression("(?:NA|([^;]*))") // params .groupEnd("?") + .any() .compile(); private void sendResponse(Channel channel, SocketAddress remoteAddress, String type, Integer number) { diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java index e67a798ff..b7c422456 100644 --- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java @@ -13,6 +13,10 @@ public class WialonProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, text( "#L#2.0;42001300083;;CE45")); + verifyAttribute(decoder, text( + "#D#220323;114150;2234.80479;N;11354.87786;E;0;NA;59;11;NA;NA;NA;;NA;d_battr:1:94,d_csq:1:21,di_light:1:1;E7C9"), + "di_light", 1.0); + verifyAttributes(decoder, text( "#D#NA;NA;5429.681944502211763;N;02654.60403650999069;E;NA;NA;NA;NA;NA;NA;NA;1.0;NA;m1:1:9196679,d1:1:15397,t1:1:20,b1:1:162,fuel1:2:21588.0,pv1:2:35.98,finish:1:1;0x9b0")); -- cgit v1.2.3 From b083371beb7b5d32b8ce91da60e10dd3cf8b4c6b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Mar 2023 09:51:52 -0700 Subject: Decode alarm code and input --- src/main/java/org/traccar/protocol/T800xProtocolDecoder.java | 2 ++ src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index 758716d23..4ddea730c 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -400,6 +400,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { int alarm = buf.readUnsignedByte(); position.set(Position.KEY_ALARM, header != 0x2727 ? decodeAlarm1(alarm) : decodeAlarm2(alarm)); + position.set("alarmCode", alarm); if (header != 0x2727) { @@ -470,6 +471,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { int inputStatus = buf.readUnsignedShort(); position.set(Position.KEY_IGNITION, BitUtil.check(inputStatus, 2)); position.set(Position.KEY_RSSI, BitUtil.between(inputStatus, 4, 11)); + position.set(Position.KEY_INPUT, inputStatus); buf.readUnsignedShort(); // ignition on upload interval buf.readUnsignedInt(); // ignition off upload interval diff --git a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java index 246687149..3f62a834c 100644 --- a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class T800xProtocolDecoderTest extends ProtocolTest { var decoder = inject(new T800xProtocolDecoder(null)); + verifyAttributes(decoder, binary( + "272704004901380864112055585747c612230321220006000036435fc8acc2ee600f420000000000000000909019003900001356a18000012c0000a8c00000001e20d4800000c00000")); + verifyAttributes(decoder, binary( "2525110055000208677300508924902206262035310c540045004c00430045004c0004454447450847534d20313930300f323134303734323036373835323839143839333430373131373930303936383037363846")); -- cgit v1.2.3 From d4efbfa2a7d9d8410540fd2b6409c4086da9cec5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 Mar 2023 16:23:12 -0700 Subject: Add JT808 driver information --- .../traccar/protocol/HuabaoProtocolDecoder.java | 23 +++++++++++++++------- .../protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index ddc3192eb..7227c5584 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -457,6 +457,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int subtype = buf.readUnsignedByte(); int length = buf.readUnsignedByte(); int endIndex = buf.readerIndex() + length; + String stringValue; switch (subtype) { case 0x01: position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); @@ -474,9 +475,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); break; case 0x33: - String sentence = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); - if (sentence.startsWith("*M00")) { - String lockStatus = sentence.substring(8, 8 + 7); + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + if (stringValue.startsWith("*M00")) { + String lockStatus = stringValue.substring(8, 8 + 7); position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01); } break; @@ -501,8 +502,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { break; case 0x94: if (length > 0) { - position.set( - Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_VIN, stringValue); } break; case 0xA7: @@ -512,6 +513,14 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0xAC: position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); break; + case 0xBC: + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set("driver", stringValue.trim()); + break; + case 0xBD: + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_DRIVER_UNIQUE_ID, stringValue); + break; case 0xD0: long userStatus = buf.readUnsignedInt(); if (BitUtil.check(userStatus, 3)) { @@ -598,8 +607,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } break; case 0xED: - String license = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim(); - position.set("driverLicense", license); + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set("driverLicense", stringValue.trim()); break; case 0xEE: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 1737593e4..4541185f4 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyAttribute(decoder, binary( + "7E02000079013653183645009E00000000000C0C030158BF0006C926670000004000CE22120904274201040000005DBC3244524956494E47204C4943454E53452454455354244D522E0000000000000000000000000000000000000000000000000000BD0F323431393939393935383030313030E3060000050500007102000C30011F310108987E"), + "driver", "DRIVING LICENSE$TEST$MR."); + verifyAttribute(decoder, binary( "7e55019c3b8571110003399a07032310302029538631031015370500001a0c000000265700440001233703080000001001020202000a0a04028f000af401040c06ff98ffa8007e707e"), "tilt", "[-104,-88,126]"); -- cgit v1.2.3 From e6960c3d49025eb63243052e4c7aedde9955fe40 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 25 Mar 2023 07:37:46 -0700 Subject: Support Wetrust GPS tracker --- src/main/java/org/traccar/model/Position.java | 2 ++ .../java/org/traccar/protocol/FifotrackProtocolDecoder.java | 8 ++++---- .../java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 12 +++++++++++- .../java/org/traccar/protocol/HuabaoProtocolDecoder.java | 2 +- .../java/org/traccar/protocol/MeiligaoProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java | 2 +- .../java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ .../java/org/traccar/protocol/TzoneProtocolDecoderTest.java | 3 ++- 10 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 41cfeaf2e..2bd71f383 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -90,6 +90,7 @@ public class Position extends Message { public static final String KEY_ICCID = "iccid"; public static final String KEY_PHONE = "phone"; public static final String KEY_SPEED_LIMIT = "speedLimit"; + public static final String KEY_DRIVING_TIME = "drivingTime"; public static final String KEY_DTCS = "dtcs"; public static final String KEY_OBD_SPEED = "obdSpeed"; // knots @@ -98,6 +99,7 @@ public class Position extends Message { public static final String KEY_RESULT = "result"; public static final String KEY_DRIVER_UNIQUE_ID = "driverUniqueId"; + public static final String KEY_CARD = "card"; // Start with 1 not 0 public static final String PREFIX_TEMP = "temp"; diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index a9d77b46e..e0dd1d62d 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -308,11 +308,11 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { } if (parser.hasNext()) { - String rfid = parser.next(); - if (rfid.matches("\\p{XDigit}+")) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(Integer.parseInt(rfid, 16))); + String value = parser.next(); + if (value.matches("\\p{XDigit}+")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(Integer.parseInt(value, 16))); } else { - position.set("driverLicense", rfid); + position.set(Position.KEY_CARD, value); } } diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 28308ab77..c7713bdc2 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -680,7 +680,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1]))); } if (BitUtil.check(reportMask, 12)) { - position.set("drivingHours", Double.parseDouble(values[index++])); + position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(values[index++])); } if (BitUtil.check(reportMask, 13)) { position.set("idleHours", Double.parseDouble(values[index++])); diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 5b639ddfc..02a629103 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -119,6 +119,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { SPACE10X, STANDARD, OBD6, + WETRUST, } private Variant variant; @@ -833,7 +834,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { String data = buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); buf.readUnsignedByte(); // alarm buf.readUnsignedByte(); // swiped - position.set("driverLicense", data.trim()); + position.set(Position.KEY_CARD, data.trim()); } else if (variant == Variant.BENWAY) { int mask = buf.readUnsignedShort(); position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7)); @@ -869,6 +870,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } position.set(Position.PREFIX_TEMP + 1, temperature); position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 10); + } else if (variant == Variant.WETRUST) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + position.set(Position.KEY_CARD, buf.readCharSequence( + buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString()); + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null); + position.set("cardStatus", buf.readUnsignedByte()); + position.set(Position.KEY_DRIVING_TIME, buf.readUnsignedShort()); } } @@ -1391,6 +1399,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.SPACE10X; } else if (header == 0x7878 && type == MSG_STATUS && length == 0x13) { variant = Variant.OBD6; + } else if (header == 0x7878 && type == MSG_GPS_LBS_1 && length == 0x29) { + variant = Variant.WETRUST; } else { variant = Variant.STANDARD; } diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 7227c5584..5e73967d5 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -608,7 +608,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { break; case 0xED: stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); - position.set("driverLicense", stringValue.trim()); + position.set(Position.KEY_CARD, stringValue.trim()); break; case 0xEE: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java index f3b56973a..1f8c4d2da 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java @@ -282,7 +282,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RSSI, parser.nextHexInt()); position.set(Position.KEY_ODOMETER, parser.nextHexLong()); position.set(Position.KEY_SATELLITES, parser.nextHexInt()); - position.set("driverLicense", parser.next()); + position.set(Position.KEY_CARD, parser.next()); position.set(Position.KEY_ODOMETER, parser.nextLong()); position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); diff --git a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java index ba9b41654..f0b1e709d 100644 --- a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java @@ -234,7 +234,7 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder { } else if (type == 1) { - position.set("driverLicense", buf.readCharSequence( + position.set(Position.KEY_CARD, buf.readCharSequence( blockEnd - buf.readerIndex(), StandardCharsets.UTF_8).toString()); } diff --git a/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java index a8fc801e7..1ad15f39c 100644 --- a/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java @@ -123,7 +123,7 @@ public class Vt200ProtocolDecoder extends BaseProtocolDecoder { position.set("tripStart", decodeDate(buf).getTime()); position.set("tripEnd", decodeDate(buf).getTime()); - position.set("drivingTime", buf.readUnsignedShort()); + position.set(Position.KEY_DRIVING_TIME, buf.readUnsignedShort()); position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 3b4cb158e..5dc6b803e 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78782912170316053b3bcf015b51220af1201105d56100000000000000000000869c0130010000000238d1af0d0a"), + Position.KEY_DRIVING_TIME, 0); + verifyAttribute(decoder, binary( "78781219012ed042cc00954d00040419000056fe290d0a"), Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); diff --git a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java index 8fdc8c23c..d90e5e07e 100644 --- a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class TzoneProtocolDecoderTest extends ProtocolTest { @@ -12,7 +13,7 @@ public class TzoneProtocolDecoderTest extends ProtocolTest { verifyAttribute(decoder, binary( "545a00d424240153011300000863835029944118170316023b180016040485c73d2479187e170316023b1800000000060c000000000d1cc0406303019904aa00000000008a012520205e544f4e474c4f4d245049544f4f4e244d522e5e5e3f3b363030373634333132303130303134323234323d3139303631393538313032363d3f2b2020202020202020202020202032322020202020202020202020203120202020202020202020202030303234363238202031303730302020202020202020202020202020202020202020203f00030080000006e80e0d0a"), - "driverLicense", "% ^TONGLOM$PITOON$MR.^^?;6007643120100142242=190619581026=?+ 22 1 0024628 10700 ?"); + Position.KEY_CARD, "% ^TONGLOM$PITOON$MR.^^?;6007643120100142242=190619581026=?+ 22 1 0024628 10700 ?"); verifyAttributes(decoder, binary( "545a003724240407020200000180322000001610160b151019100000000c010a07320101088600007dca000baa102837016a0114025500000169e80d0a")); -- cgit v1.2.3 From 3082f7b3e5bfd00ec6f6801222060dfc0d10b7e0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Mar 2023 06:54:29 -0700 Subject: Implement group commands --- .../org/traccar/api/resource/CommandResource.java | 20 ++++++--- .../java/org/traccar/helper/model/DeviceUtil.java | 48 +++++++++++++++++++++- .../traccar/reports/CombinedReportProvider.java | 3 +- .../org/traccar/reports/EventsReportProvider.java | 5 ++- .../org/traccar/reports/RouteReportProvider.java | 5 ++- .../org/traccar/reports/StopsReportProvider.java | 5 ++- .../org/traccar/reports/SummaryReportProvider.java | 3 +- .../org/traccar/reports/TripsReportProvider.java | 5 ++- .../org/traccar/reports/common/ReportUtils.java | 40 ------------------ 9 files changed, 78 insertions(+), 56 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index 3460cf6e0..7ba1ee2b4 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -23,8 +23,10 @@ import org.traccar.BaseProtocol; import org.traccar.ServerManager; import org.traccar.api.ExtendedObjectResource; import org.traccar.database.CommandsManager; +import org.traccar.helper.model.DeviceUtil; import org.traccar.model.Command; import org.traccar.model.Device; +import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.model.Typed; import org.traccar.model.User; @@ -104,7 +106,7 @@ public class CommandResource extends ExtendedObjectResource { @POST @Path("send") - public Response send(Command entity) throws Exception { + public Response send(Command entity, @QueryParam("groupId") long groupId) throws Exception { if (entity.getId() > 0) { permissionsService.checkPermission(baseClass, getUserId(), entity.getId()); long deviceId = entity.getDeviceId(); @@ -114,11 +116,19 @@ public class CommandResource extends ExtendedObjectResource { } else { permissionsService.checkRestriction(getUserId(), UserRestrictions::getLimitCommands); } - permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); - if (!commandsManager.sendCommand(entity)) { - return Response.accepted(entity).build(); + boolean result = true; + if (groupId > 0) { + permissionsService.checkPermission(Group.class, getUserId(), groupId); + var devices = DeviceUtil.getAccessibleDevices(storage, getUserId(), List.of(), List.of(groupId)); + for (Device device : devices) { + entity.setDeviceId(device.getId()); + result = result && commandsManager.sendCommand(entity); + } + } else { + permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); + result = commandsManager.sendCommand(entity); } - return Response.ok(entity).build(); + return result ? Response.ok(entity).build() : Response.accepted(entity).build(); } @GET diff --git a/src/main/java/org/traccar/helper/model/DeviceUtil.java b/src/main/java/org/traccar/helper/model/DeviceUtil.java index 597078caf..5d8cb5f25 100644 --- a/src/main/java/org/traccar/helper/model/DeviceUtil.java +++ b/src/main/java/org/traccar/helper/model/DeviceUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -16,11 +16,20 @@ package org.traccar.helper.model; import org.traccar.model.Device; +import org.traccar.model.Group; +import org.traccar.model.User; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.Objects; +import java.util.stream.Collectors; + public final class DeviceUtil { private DeviceUtil() { @@ -30,4 +39,41 @@ public final class DeviceUtil { storage.updateObject(new Device(), new Request(new Columns.Include("status"))); } + + public static Collection getAccessibleDevices( + Storage storage, long userId, + Collection deviceIds, Collection groupIds) throws StorageException { + + var devices = storage.getObjects(Device.class, new Request( + new Columns.All(), + new Condition.Permission(User.class, userId, Device.class))); + var deviceById = devices.stream() + .collect(Collectors.toUnmodifiableMap(Device::getId, x -> x)); + var devicesByGroup = devices.stream() + .filter(x -> x.getGroupId() > 0) + .collect(Collectors.groupingBy(Device::getGroupId)); + + var groups = storage.getObjects(Group.class, new Request( + new Columns.All(), + new Condition.Permission(User.class, userId, Group.class))); + var groupsByGroup = groups.stream() + .filter(x -> x.getGroupId() > 0) + .collect(Collectors.groupingBy(Group::getGroupId)); + + var results = deviceIds.stream() + .map(deviceById::get) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + var groupQueue = new LinkedList<>(groupIds); + while (!groupQueue.isEmpty()) { + long groupId = groupQueue.pop(); + results.addAll(devicesByGroup.getOrDefault(groupId, Collections.emptyList())); + groupQueue.addAll(groupsByGroup.getOrDefault(groupId, Collections.emptyList()) + .stream().map(Group::getId).collect(Collectors.toUnmodifiableList())); + } + + return results; + } + } diff --git a/src/main/java/org/traccar/reports/CombinedReportProvider.java b/src/main/java/org/traccar/reports/CombinedReportProvider.java index 923fd12b4..63d6a9830 100644 --- a/src/main/java/org/traccar/reports/CombinedReportProvider.java +++ b/src/main/java/org/traccar/reports/CombinedReportProvider.java @@ -15,6 +15,7 @@ */ package org.traccar.reports; +import org.traccar.helper.model.DeviceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Event; @@ -53,7 +54,7 @@ public class CombinedReportProvider { reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { CombinedReportItem item = new CombinedReportItem(); item.setDeviceId(device.getId()); var positions = PositionUtil.getPositions(storage, device.getId(), from, to); diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java index 30f55ba80..ff7bc8e2f 100644 --- a/src/main/java/org/traccar/reports/EventsReportProvider.java +++ b/src/main/java/org/traccar/reports/EventsReportProvider.java @@ -19,6 +19,7 @@ package org.traccar.reports; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.helper.model.DeviceUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; @@ -76,7 +77,7 @@ public class EventsReportProvider { reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { Collection events = getEvents(device.getId(), from, to); boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); for (Event event : events) { @@ -104,7 +105,7 @@ public class EventsReportProvider { HashMap geofenceNames = new HashMap<>(); HashMap maintenanceNames = new HashMap<>(); HashMap positions = new HashMap<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { Collection events = getEvents(device.getId(), from, to); boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); for (Iterator iterator = events.iterator(); iterator.hasNext();) { diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index 3ee651619..6d44259e6 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -19,6 +19,7 @@ package org.traccar.reports; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.helper.model.DeviceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; @@ -60,7 +61,7 @@ public class RouteReportProvider { reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { result.addAll(PositionUtil.getPositions(storage, device.getId(), from, to)); } return result; @@ -73,7 +74,7 @@ public class RouteReportProvider { ArrayList devicesRoutes = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { var positions = PositionUtil.getPositions(storage, device.getId(), from, to); DeviceReportSection deviceRoutes = new DeviceReportSection(); deviceRoutes.setDeviceName(device.getName()); diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index ec3fd2215..a23cee48b 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -19,6 +19,7 @@ package org.traccar.reports; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.helper.model.DeviceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; @@ -67,7 +68,7 @@ public class StopsReportProvider { reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { result.addAll(detectStops(device, from, to)); } return result; @@ -80,7 +81,7 @@ public class StopsReportProvider { ArrayList devicesStops = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { Collection stops = detectStops(device, from, to); DeviceReportSection deviceStops = new DeviceReportSection(); deviceStops.setDeviceName(device.getName()); diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index 9415f3e81..f7d9f0325 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -21,6 +21,7 @@ import org.traccar.api.security.PermissionsService; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.DeviceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.helper.model.UserUtil; import org.traccar.model.Device; @@ -146,7 +147,7 @@ public class SummaryReportProvider { reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { Collection deviceResults = calculateSummaryResults(userId, device, from, to, daily); for (SummaryReportItem summaryReport : deviceResults) { if (summaryReport.getStartTime() != null && summaryReport.getEndTime() != null) { diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index 265811354..2d8989b7a 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -19,6 +19,7 @@ package org.traccar.reports; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.helper.model.DeviceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; @@ -67,7 +68,7 @@ public class TripsReportProvider { reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { result.addAll(detectTrips(device, from, to)); } return result; @@ -80,7 +81,7 @@ public class TripsReportProvider { ArrayList devicesTrips = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); - for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) { + for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { Collection trips = detectTrips(device, from, to); DeviceReportSection deviceTrips = new DeviceReportSection(); deviceTrips.setDeviceName(device.getName()); diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 35faa9c8b..f1a2f7d54 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -36,7 +36,6 @@ import org.traccar.helper.model.UserUtil; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Driver; -import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.reports.model.BaseReportItem; @@ -60,13 +59,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Date; -import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.Objects; -import java.util.stream.Collectors; @Singleton public class ReportUtils { @@ -106,41 +101,6 @@ public class ReportUtils { } } - public Collection getAccessibleDevices( - long userId, Collection deviceIds, Collection groupIds) throws StorageException { - - var devices = storage.getObjects(Device.class, new Request( - new Columns.All(), - new Condition.Permission(User.class, userId, Device.class))); - var deviceById = devices.stream() - .collect(Collectors.toUnmodifiableMap(Device::getId, x -> x)); - var devicesByGroup = devices.stream() - .filter(x -> x.getGroupId() > 0) - .collect(Collectors.groupingBy(Device::getGroupId)); - - var groups = storage.getObjects(Group.class, new Request( - new Columns.All(), - new Condition.Permission(User.class, userId, Group.class))); - var groupsByGroup = groups.stream() - .filter(x -> x.getGroupId() > 0) - .collect(Collectors.groupingBy(Group::getGroupId)); - - var results = deviceIds.stream() - .map(deviceById::get) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); - - var groupQueue = new LinkedList<>(groupIds); - while (!groupQueue.isEmpty()) { - long groupId = groupQueue.pop(); - results.addAll(devicesByGroup.getOrDefault(groupId, Collections.emptyList())); - groupQueue.addAll(groupsByGroup.getOrDefault(groupId, Collections.emptyList()) - .stream().map(Group::getId).collect(Collectors.toUnmodifiableList())); - } - - return results; - } - public double calculateFuel(Position firstPosition, Position lastPosition) { if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null -- cgit v1.2.3 From 7c67b6f9b46a350ae111eff2caea5981dc0e1bff Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Mar 2023 07:07:46 -0700 Subject: Fix map testing script --- tools/test-map.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/test-map.py b/tools/test-map.py index 362c95878..664917eff 100755 --- a/tools/test-map.py +++ b/tools/test-map.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import urllib -import urllib2 +import urllib.request as urllib2 import http.client as httplib import time import random @@ -14,7 +14,7 @@ devices = 500 def login(): request = urllib2.Request(baseUrl + '/api/session') - response = urllib2.urlopen(request, urllib.parse.urlencode(user)) + response = urllib2.urlopen(request, urllib.parse.urlencode(user).encode()) return response.headers.get('Set-Cookie') def add_device(cookie, unique_id): @@ -23,7 +23,7 @@ def add_device(cookie, unique_id): request.add_header('Content-Type', 'application/json') device = { 'name' : unique_id, 'uniqueId' : unique_id } try: - response = urllib2.urlopen(request, json.dumps(device)) + response = urllib2.urlopen(request, json.dumps(device).encode()) except urllib2.HTTPError: pass -- cgit v1.2.3 From ac60477392048413d97a6d54a4456647aaaf7d22 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Mar 2023 09:55:07 -0700 Subject: Implement VLT protocol --- gradle/checkstyle.xml | 2 +- setup/default.xml | 1 + .../java/org/traccar/protocol/VltProtocol.java | 43 +++++++ .../org/traccar/protocol/VltProtocolDecoder.java | 137 +++++++++++++++++++++ .../traccar/protocol/VltProtocolDecoderTest.java | 22 ++++ 5 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/traccar/protocol/VltProtocol.java create mode 100644 src/main/java/org/traccar/protocol/VltProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java diff --git a/gradle/checkstyle.xml b/gradle/checkstyle.xml index a6a6f0ff7..bb89450d6 100644 --- a/gradle/checkstyle.xml +++ b/gradle/checkstyle.xml @@ -114,7 +114,7 @@ - + diff --git a/setup/default.xml b/setup/default.xml index 75acf25a1..ff8ecf589 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -287,5 +287,6 @@ 5243 5244 5245 + 5246 diff --git a/src/main/java/org/traccar/protocol/VltProtocol.java b/src/main/java/org/traccar/protocol/VltProtocol.java new file mode 100644 index 000000000..ebced83b1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VltProtocol.java @@ -0,0 +1,43 @@ +/* + * 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.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import javax.inject.Inject; + +public class VltProtocol extends BaseProtocol { + + @Inject + public VltProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new VltProtocolDecoder(VltProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/VltProtocolDecoder.java b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java new file mode 100644 index 000000000..8890dece1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java @@ -0,0 +1,137 @@ +/* + * 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.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class VltProtocolDecoder extends BaseHttpProtocolDecoder { + + public VltProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(dd)") // alert id + .expression("([HL])") // history + .number("([01])") // validity + .number("(dd)(dd)(dd)") // date (ddmmyy) + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(d{3}.d{6})([NS])") // latitude + .number("(d{3}.d{6})([EW])") // longitude + .number("(d{3})") // mcc + .expression("(x*[0-9]+)") // mnc + .number("(x{4})") // lac + .number("(d{9})") // cid + .number("(d{3}.d{2})") // speed + .number("(d{3}.d{2})") // course + .number("(d{2})") // satellites + .number("(d{2})") // hdop + .number("(d{2})") // rssi + .number("([01])") // ignition + .number("([01])") // charging + .expression("([HMS])") // vehicle mode + .compile(); + + private Position decodePosition(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, parser.nextInt()); + position.set(Position.KEY_ARCHIVE, parser.next().equals("H") ? true : null); + + position.setValid(parser.nextInt() > 0); + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + + int mcc = parser.nextInt(); + int mnc = Integer.parseInt(parser.next().replaceAll("x", "")); + int lac = parser.nextHexInt(); + int cid = parser.nextInt(); + + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextInt()); + + position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid, parser.nextInt()))); + + position.set(Position.KEY_IGNITION, parser.nextInt() > 0); + position.set(Position.KEY_CHARGE, parser.nextInt() > 0); + position.set(Position.KEY_MOTION, parser.next().equals("M")); + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + QueryStringDecoder decoder = new QueryStringDecoder( + request.content().toString(StandardCharsets.US_ASCII), false); + String sentence = decoder.parameters().get("vltdata").iterator().next(); + + int index = 0; + String type = sentence.substring(index, index += 3); + String imei = sentence.substring(index, index += 15); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + sendResponse(channel, HttpResponseStatus.OK); + + switch (type) { + case "NRM": + return decodePosition(deviceSession, sentence.substring(3 + 15)); + default: + List positions = new LinkedList<>(); + int count = Integer.parseInt(sentence.substring(index, index += 3)); + for (int i = 0; i < count; i++) { + positions.add(decodePosition(deviceSession, sentence.substring(index, index += 78))); + } + return positions; + } + } + +} diff --git a/src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java new file mode 100644 index 000000000..e0e88b324 --- /dev/null +++ b/src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class VltProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new VltProtocolDecoder(null)); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("vltdata=NRM12345678901234501L1060418102230023.125503N080.068033E4041231234123456789070.48120.5025273011M"))); + + verifyPositions(decoder, request(HttpMethod.POST, "/", + buffer("vltdata=BTH86123004167306301301L1240323181909009.226018N076.794980E404x19601d000037596000.00198.7013011401S02H1240323181807009.226018N076.794980E404x72090a000000000000.00198.7013011101S02H1240323181707009.226018N076.794980E404x72090a000014598000.00198.7013011101S02H1240323181605009.226018N076.794982E404x72090a000014596000.00198.7013011101S02H1240323181504009.226018N076.794982E404x72090a000014596000.00198.7013010901S02H1240323181402009.226018N076.794980E404x72090a000014596001.67198.0013021301S02H1240323181306009.226010N076.794980E404x72090a000014596000.00174.0013021401S02H1240323181155009.226010N076.794980E404x72090a088511008000.00174.0013011201S02H1240323181057009.226010N076.794980E404x72090a000014596000.00174.0013011201S02H1240323180958009.226010N076.794980E404x72090a000014596000.00174.0013021401S02H1240323180858009.226010N076.794980E404x72090a000014596001.48174.0013021201S02H1240323180755009.226005N076.794982E404x72090a000014598000.00164.4013011301S02H1240323180652009.226005N076.794982E404x72090a000014598000.00164.4013021101S"))); + + } + +} -- cgit v1.2.3 From a5a2a3f69fd76602f5577354cde653915e8d8ad4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Mar 2023 07:33:28 -0700 Subject: Fix VLT type decoding --- src/main/java/org/traccar/protocol/VltProtocolDecoder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/VltProtocolDecoder.java b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java index 8890dece1..01c0563f5 100644 --- a/src/main/java/org/traccar/protocol/VltProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java @@ -124,13 +124,15 @@ public class VltProtocolDecoder extends BaseHttpProtocolDecoder { switch (type) { case "NRM": return decodePosition(deviceSession, sentence.substring(3 + 15)); - default: + case "BTH": List positions = new LinkedList<>(); int count = Integer.parseInt(sentence.substring(index, index += 3)); for (int i = 0; i < count; i++) { positions.add(decodePosition(deviceSession, sentence.substring(index, index += 78))); } return positions; + default: + return null; } } -- cgit v1.2.3 From 7aa7d2d98e2fd7fb36c50711bf6e547c829d6d58 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Mar 2023 09:19:53 -0700 Subject: Flespi battery level support --- src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java index 6e6f9c700..a7f6c284a 100644 --- a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java @@ -125,12 +125,10 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { position.set(Position.KEY_PDOP, ((JsonNumber) value).doubleValue()); return true; case "din": + position.set(Position.KEY_INPUT, ((JsonNumber) value).intValue()); + return true; case "dout": - if (name.equals("din")) { - position.set(Position.KEY_INPUT, ((JsonNumber) value).intValue()); - } else { - position.set(Position.KEY_OUTPUT, ((JsonNumber) value).intValue()); - } + position.set(Position.KEY_OUTPUT, ((JsonNumber) value).intValue()); return true; case "gps.vehicle.mileage": position.set(Position.KEY_ODOMETER, ((JsonNumber) value).doubleValue()); @@ -141,6 +139,9 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { case "battery.voltage": position.set(Position.KEY_BATTERY, ((JsonNumber) value).doubleValue()); return true; + case "battery.level": + position.set(Position.KEY_BATTERY_LEVEL, ((JsonNumber) value).intValue()); + return true; case "fuel.level": case "can.fuel.level": position.set(Position.KEY_FUEL_LEVEL, ((JsonNumber) value).doubleValue()); -- cgit v1.2.3 From 56c6fd3cfa7140d899ff8e964754e856a8c8b0d8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Mar 2023 09:52:16 -0700 Subject: Check disabled users --- src/main/java/org/traccar/api/security/SecurityRequestFilter.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index 9992d49e7..e6641548a 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -15,6 +15,7 @@ */ package org.traccar.api.security; +import com.google.inject.Injector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.api.resource.SessionResource; @@ -63,6 +64,9 @@ public class SecurityRequestFilter implements ContainerRequestFilter { @Inject private StatisticsManager statisticsManager; + @Inject + private Injector injector; + @Override public void filter(ContainerRequestContext requestContext) { @@ -97,13 +101,14 @@ 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)); } } - } catch (SecurityException e) { + } catch (SecurityException | StorageException e) { LOGGER.warn("Authentication error", e); } -- cgit v1.2.3 From 1d1fc57b3dd44013bd467a825b970ac06749e125 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Mar 2023 17:53:19 -0700 Subject: Handle Firebase failures --- .../traccar/notificators/NotificatorFirebase.java | 52 +++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index 9fa2ebaf3..d80354d7d 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -25,7 +25,10 @@ import com.google.firebase.messaging.ApnsConfig; import com.google.firebase.messaging.Aps; import com.google.firebase.messaging.FirebaseMessaging; import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.MessagingErrorCode; import com.google.firebase.messaging.MulticastMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; @@ -34,24 +37,40 @@ import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; +import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.inject.Inject; import javax.inject.Singleton; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedList; import java.util.List; @Singleton public class NotificatorFirebase implements Notificator { + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class); + private final NotificationFormatter notificationFormatter; + private final Storage storage; + private final CacheManager cacheManager; @Inject - public NotificatorFirebase(Config config, NotificationFormatter notificationFormatter) throws IOException { + public NotificatorFirebase( + Config config, NotificationFormatter notificationFormatter, + Storage storage, CacheManager cacheManager) throws IOException { this.notificationFormatter = notificationFormatter; + this.storage = storage; + this.cacheManager = cacheManager; InputStream serviceAccount = new ByteArrayInputStream( config.getString(Keys.NOTIFICATOR_FIREBASE_SERVICE_ACCOUNT).getBytes()); @@ -69,7 +88,8 @@ public class NotificatorFirebase implements Notificator { var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); - List registrationTokens = Arrays.asList(user.getString("notificationTokens").split("[, ]")); + List registrationTokens = new ArrayList<>( + Arrays.asList(user.getString("notificationTokens").split("[, ]"))); MulticastMessage message = MulticastMessage.builder() .setNotification(com.google.firebase.messaging.Notification.builder() @@ -92,13 +112,33 @@ public class NotificatorFirebase implements Notificator { try { var result = FirebaseMessaging.getInstance().sendMulticast(message); - for (var response : result.getResponses()) { + List failedTokens = new LinkedList<>(); + var iterator = result.getResponses().listIterator(); + while (iterator.hasNext()) { + int index = iterator.nextIndex(); + var response = iterator.next(); if (!response.isSuccessful()) { - throw new MessageException(response.getException()); + MessagingErrorCode error = response.getException().getMessagingErrorCode(); + if (error == MessagingErrorCode.INVALID_ARGUMENT || error == MessagingErrorCode.UNREGISTERED) { + failedTokens.add(registrationTokens.get(index)); + } + LOGGER.warn("Firebase user {} error", user.getId(), response.getException()); + } + } + if (!failedTokens.isEmpty()) { + registrationTokens.removeAll(failedTokens); + if (registrationTokens.isEmpty()) { + user.getAttributes().remove("notificationTokens"); + } else { + user.set("notificationTokens", String.join(",", registrationTokens)); } + storage.updateObject(user, new Request( + new Columns.Include("attributes"), + new Condition.Equals("id", user.getId()))); + cacheManager.updateOrInvalidate(true, user); } - } catch (FirebaseMessagingException e) { - throw new MessageException(e); + } catch (FirebaseMessagingException | StorageException e) { + LOGGER.warn("Firebase error", e); } } } -- cgit v1.2.3 From c68e92043cb52f859de724781f2e5774c60d465b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Mar 2023 20:05:05 -0700 Subject: Add HuaSheng output control --- .../org/traccar/protocol/HuaShengProtocol.java | 1 + .../traccar/protocol/HuaShengProtocolDecoder.java | 2 ++ .../traccar/protocol/HuaShengProtocolEncoder.java | 22 ++++++++++++++++++---- .../protocol/HuaShengProtocolEncoderTest.java | 12 +++++++++++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocol.java b/src/main/java/org/traccar/protocol/HuaShengProtocol.java index 4a0ebe5d7..1f8bafc57 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocol.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocol.java @@ -29,6 +29,7 @@ public class HuaShengProtocol extends BaseProtocol { public HuaShengProtocol(Config config) { setSupportedDataCommands( Command.TYPE_POSITION_PERIODIC, + Command.TYPE_OUTPUT_CONTROL, Command.TYPE_ALARM_ARM, Command.TYPE_ALARM_DISARM, Command.TYPE_SET_SPEED_LIMIT); diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 993e36978..2d952c759 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -50,6 +50,8 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_HSO_RSP = 0x0003; public static final int MSG_SET_REQ = 0xAA04; public static final int MSG_SET_RSP = 0xFF05; + public static final int MSG_CTRL_REQ = 0xAA16; + public static final int MSG_CTRL_RSP = 0xFF17; private void sendResponse(Channel channel, int type, int index, ByteBuf content) { if (channel != null) { diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java index 636196ec4..dc34f7b4e 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java @@ -27,13 +27,13 @@ public class HuaShengProtocolEncoder extends BaseProtocolEncoder { super(protocol); } - private ByteBuf encodeContent(ByteBuf content) { + private ByteBuf encodeContent(int type, ByteBuf content) { ByteBuf buf = Unpooled.buffer(); buf.writeByte(0xC0); buf.writeShort(0x0000); // flag and version buf.writeShort(12 + content.readableBytes()); - buf.writeShort(HuaShengProtocolDecoder.MSG_SET_REQ); + buf.writeShort(type); buf.writeShort(0); // checksum buf.writeInt(1); // index buf.writeBytes(content); @@ -52,17 +52,31 @@ public class HuaShengProtocolEncoder extends BaseProtocolEncoder { content.writeShort(0x0002); content.writeShort(6); // length content.writeShort(command.getInteger(Command.KEY_FREQUENCY)); - return encodeContent(content); + return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content); + case Command.TYPE_OUTPUT_CONTROL: + /* +0x01: Lock the relay1; //relay on +0x02: Unlock the relay1; //relay off +0x03: Lock the relay2; //relay2 on +0x04: Unlock the relay2; //relay2 off +0x05: Lock the relay3; //relay3 on +0x06: Unlock the relay3; //realy3 off + */ + content.writeByte( + (command.getInteger(Command.KEY_INDEX) - 1) * 2 + + (2 - command.getInteger(Command.KEY_DATA))); + return encodeContent(HuaShengProtocolDecoder.MSG_CTRL_REQ, content); case Command.TYPE_ALARM_ARM: case Command.TYPE_ALARM_DISARM: content.writeShort(0x0001); content.writeShort(5); // length content.writeByte(command.getType().equals(Command.TYPE_ALARM_ARM) ? 1 : 0); + return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content); case Command.TYPE_SET_SPEED_LIMIT: content.writeShort(0x0004); content.writeShort(6); // length content.writeShort(command.getInteger(Command.KEY_DATA)); - return encodeContent(content); + return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content); default: return null; } diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java index b44f6e89c..c320d4aa9 100644 --- a/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java @@ -11,7 +11,17 @@ public class HuaShengProtocolEncoderTest extends ProtocolTest { var encoder = inject(new HuaShengProtocolEncoder(null)); - Command command = new Command(); + Command command; + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_OUTPUT_CONTROL); + command.set(Command.KEY_INDEX, 1); + command.set(Command.KEY_DATA, "1"); + + verifyCommand(encoder, command, binary("c00000000daa1600000000000101c0")); + + command = new Command(); command.setDeviceId(1); command.setType(Command.TYPE_POSITION_PERIODIC); command.set(Command.KEY_FREQUENCY, 60); -- cgit v1.2.3 From 074ed6014cc7e243ce907052dc86444c0d23ccdd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 28 Mar 2023 09:10:53 -0700 Subject: Handle Traccar push errors --- .../traccar/notificators/NotificatorTraccar.java | 60 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index e32229506..fb9632ad0 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java @@ -16,23 +16,41 @@ package org.traccar.notificators; import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; +import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.inject.Inject; import javax.inject.Singleton; +import javax.json.JsonObject; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; @Singleton public class NotificatorTraccar implements Notificator { + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorTraccar.class); + private final NotificationFormatter notificationFormatter; private final Client client; + private final Storage storage; + private final CacheManager cacheManager; private final String url; private final String key; @@ -54,9 +72,13 @@ public class NotificatorTraccar implements Notificator { } @Inject - public NotificatorTraccar(Config config, NotificationFormatter notificationFormatter, Client client) { + public NotificatorTraccar( + Config config, NotificationFormatter notificationFormatter, Client client, + Storage storage, CacheManager cacheManager) { this.notificationFormatter = notificationFormatter; this.client = client; + this.storage = storage; + this.cacheManager = cacheManager; this.url = "https://www.traccar.org/push/"; this.key = config.getString(Keys.NOTIFICATOR_TRACCAR_KEY); } @@ -72,11 +94,45 @@ public class NotificatorTraccar implements Notificator { item.body = shortMessage.getBody(); item.sound = "default"; + String[] tokenArray = user.getString("notificationTokens").split("[, ]"); + List registrationTokens = new ArrayList<>(Arrays.asList(tokenArray)); + Message message = new Message(); message.tokens = user.getString("notificationTokens").split("[, ]"); message.notification = item; - client.target(url).request().header("Authorization", "key=" + key).post(Entity.json(message)).close(); + var request = client.target(url).request().header("Authorization", "key=" + key); + try (Response result = request.post(Entity.json(message))) { + var json = result.readEntity(JsonObject.class); + List failedTokens = new LinkedList<>(); + var responses = json.getJsonArray("responses"); + for (int i = 0; i < responses.size(); i++) { + var response = responses.getJsonObject(i); + if (!response.getBoolean("success")) { + var error = response.getJsonObject("error"); + String errorCode = error.getString("code"); + if (errorCode.equals("messaging/invalid-argument") + || errorCode.equals("messaging/registration-token-not-registered")) { + failedTokens.add(registrationTokens.get(i)); + } + LOGGER.warn("Push user {} error - {}", user.getId(), error.getString("message")); + } + } + if (!failedTokens.isEmpty()) { + registrationTokens.removeAll(failedTokens); + if (registrationTokens.isEmpty()) { + user.getAttributes().remove("notificationTokens"); + } else { + user.set("notificationTokens", String.join(",", registrationTokens)); + } + storage.updateObject(user, new Request( + new Columns.Include("attributes"), + new Condition.Equals("id", user.getId()))); + cacheManager.updateOrInvalidate(true, user); + } + } catch (StorageException e) { + LOGGER.warn("Push error", e); + } } } -- cgit v1.2.3 From a91696336f2ed1fa38e3a945e77857e8e8f98461 Mon Sep 17 00:00:00 2001 From: wkhaksar <31837615+wkhaksar@users.noreply.github.com> Date: Fri, 31 Mar 2023 11:14:55 +0000 Subject: permission-check-fixed --- src/main/java/org/traccar/api/resource/PermissionsResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java index d35cb98bb..f02c5d426 100644 --- a/src/main/java/org/traccar/api/resource/PermissionsResource.java +++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java @@ -48,7 +48,7 @@ public class PermissionsResource extends BaseResource { private void checkPermission(Permission permission) throws StorageException { if (permissionsService.notAdmin(getUserId())) { permissionsService.checkPermission(permission.getOwnerClass(), getUserId(), permission.getOwnerId()); - permissionsService.checkPermission(permission.getOwnerClass(), getUserId(), permission.getOwnerId()); + permissionsService.checkPermission(permission.getPropertyClass(), getUserId(), permission.getPropertyId()); } } -- cgit v1.2.3 From c8ff1f5259b497be7da8d104fee993d14b27032d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 31 Mar 2023 06:54:23 -0700 Subject: Update API documentation --- swagger.json | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/swagger.json b/swagger.json index 229296c1a..24da5e8cd 100644 --- a/swagger.json +++ b/swagger.json @@ -764,15 +764,9 @@ "required": true }, "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - } + "204": { + "description": "No Content", + "content": {} }, "400": { "description": "No permission", @@ -786,16 +780,6 @@ "tags": [ "Permissions" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - }, - "required": true - }, "responses": { "204": { "description": "No Content", -- cgit v1.2.3 From c2dad387cb769284b279d8f0738a3f5b04c7819b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 31 Mar 2023 07:05:21 -0700 Subject: Fix API docs --- swagger.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/swagger.json b/swagger.json index 24da5e8cd..6c1e21d28 100644 --- a/swagger.json +++ b/swagger.json @@ -780,6 +780,16 @@ "tags": [ "Permissions" ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Permission" + } + } + }, + "required": true + }, "responses": { "204": { "description": "No Content", -- cgit v1.2.3 From 5c26f25b3b0afc509c76bfc4a111dbc383efee26 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 31 Mar 2023 17:26:13 -0700 Subject: Multiple battery levels --- .../org/traccar/protocol/MeitrackProtocolDecoder.java | 15 +++++++-------- .../org/traccar/protocol/MeitrackProtocolDecoderTest.java | 4 ++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 3f1f7f506..0f0d22021 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -554,15 +554,14 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(length - 2); break; case 0xFEA8: - if (buf.readUnsignedByte() > 0) { - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); - } else { - buf.readUnsignedByte(); + for (int k = 1; k <= 3; k++) { + if (buf.readUnsignedByte() > 0) { + String key = k == 1 ? Position.KEY_BATTERY_LEVEL : "battery" + k + "Level"; + position.set(key, buf.readUnsignedByte()); + } else { + buf.readUnsignedByte(); + } } - buf.readUnsignedByte(); // battery 2 status - buf.readUnsignedByte(); // battery 2 level - buf.readUnsignedByte(); // battery 3 status - buf.readUnsignedByte(); // battery 3 level buf.readUnsignedByte(); // battery alert break; default: diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 1697fc920..8d2aee501 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "2424683136342C3836363334343035333039353238322C4343452C000000000100820018000505000600070B14001500080800000900000A00000B00001606001A0000402300FE90000006022E79570103E55CCC0604E1FDB32B0CC32C00000D58EB02001C01000000050E0CCC010000B627BF11000000004B1001010D475052532847534D2039303029FEA50601FFFFFF7FFFFEA80701010258023800FEB20501010000002A41360D0A"), + "battery2Level", 88); + verifyAttribute(decoder, binary( "2424593434312c3836353431333035303839313733372c4343452c00000000030088001800050501061607191400150008080000098e000a05000b0c001608001a0000402300fe9000000602c3fe5ffe03e22a1f0904e6688d2b0cd94002000d5f6f03001c01000000050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000083001700050501061607191400150008080000098e000a05000b0c001608001a0000405100fe9000000502c3fe5ffe03e22a1f0904e6688d2b0cd94002000d606f0300050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000088001800050501061607151400150008080000098e000a05000b0c001607001a0000402300fe9000000602c3fe5ffe03e22a1f0904f0688d2b0cd94002000d696f03001c01000000050e0cf901010032700298c80897ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501000000002a36320d0a"), Position.KEY_BATTERY_LEVEL, 77); -- cgit v1.2.3 From 836fb2221dedae55c3f8457f35294b3753f095c8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 31 Mar 2023 17:48:05 -0700 Subject: Additional HHD parameters --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 5e73967d5..f13299169 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -333,9 +333,16 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // power level position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); break; + case 0x60: + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + buf.skipBytes(length - 2); + break; case 0x61: position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); break; + case 0x69: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + break; case 0x80: position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); break; -- cgit v1.2.3 From 21ccdb1234407fb17f7b96245fb7aab770fa3cbd Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 16:48:50 +0100 Subject: Add OIDC config keys --- src/main/java/org/traccar/config/Keys.java | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index c207efb1e..77aa9a635 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -610,6 +610,62 @@ public final class Keys { "ldap.adminGroup", List.of(KeyType.CONFIG)); + + /** + * OIDC enable. + */ + public static final ConfigKey OIDC_ENABLE = new BooleanConfigKey( + "oidc.enable", + List.of(KeyType.CONFIG)); + + /** + * Force OIDC authentication. + */ + public static final ConfigKey OIDC_FORCE = new BooleanConfigKey( + "oidc.force", + List.of(KeyType.CONFIG)); + + /** + * OIDC Client ID. + */ + public static final ConfigKey OIDC_CLIENTID = new StringConfigKey( + "oidc.clientId", + List.of(KeyType.CONFIG)); + + /** + * OIDC Client Secret. + */ + public static final ConfigKey OIDC_CLIENTSECRET = new StringConfigKey( + "oidc.clientSecret", + List.of(KeyType.CONFIG)); + + /** + * OIDC Authorization URL. + */ + public static final ConfigKey OIDC_AUTHURL = new StringConfigKey( + "oidc.authUrl", + List.of(KeyType.CONFIG)); + /** + * OIDC Token URL. + */ + public static final ConfigKey OIDC_TOKENURL = new StringConfigKey( + "oidc.tokenUrl", + List.of(KeyType.CONFIG)); + + /** + * OIDC User Info URL. + */ + public static final ConfigKey OIDC_USERINFOURL = new StringConfigKey( + "oidc.userInfoUrl", + List.of(KeyType.CONFIG)); + + /** + * OIDC group to grant admin access. + */ + public static final ConfigKey OIDC_ADMINGROUP = new StringConfigKey( + "oidc.adminGroup", + List.of(KeyType.CONFIG)); + /** * If no data is reported by a device for the given amount of time, status changes from online to unknown. Value is * in seconds. Default timeout is 10 minutes. -- cgit v1.2.3 From 1edce2477fde4ef8b626cf51ea175f86f63dd308 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 17:08:55 +0100 Subject: Create OIDC class and add provider to MainModule --- src/main/java/org/traccar/MainModule.java | 10 +++++ .../org/traccar/api/security/OpenIDProvider.java | 44 ++++++++++++++++++++++ src/main/java/org/traccar/config/Keys.java | 4 +- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/traccar/api/security/OpenIDProvider.java diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 663747de1..417844f50 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -87,6 +87,7 @@ import org.traccar.storage.DatabaseStorage; import org.traccar.storage.MemoryStorage; import org.traccar.storage.Storage; import org.traccar.web.WebServer; +import org.traccar.api.security.OpenIDProvider; import javax.annotation.Nullable; import javax.inject.Singleton; @@ -169,6 +170,15 @@ public class MainModule extends AbstractModule { } return null; } + + @Singleton + @Provides + public static OpenIDProvider provideOpenIDProvider(Config config) { + if (config.getBoolean(Keys.OIDC_ENABLE)) { + return new OpenIDProvider(config); + } + return null; + } @Provides public static WebServer provideWebServer(Injector injector, Config config) { diff --git a/src/main/java/org/traccar/api/security/OpenIDProvider.java b/src/main/java/org/traccar/api/security/OpenIDProvider.java new file mode 100644 index 000000000..4eaf9ac21 --- /dev/null +++ b/src/main/java/org/traccar/api/security/OpenIDProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright 2017 - 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.api.security; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.User; + +public class OpenIDProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(OpenIDProvider.class); + + private final Boolean force; + private final String clientId; + private final String authUrl; + private final String tokenUrl; + private final String userInfoUrl; + private final String adminGroup; + + public OpenIDProvider(Config config) { + force = config.getBoolean(Keys.OIDC_FORCE); + clientId = config.getString(Keys.OIDC_CLIENTID); + authUrl = config.getString(Keys.OIDC_AUTHURL); + tokenUrl = config.getString(Keys.OIDC_TOKENURL); + userInfoUrl = config.getString(Keys.OIDC_USERINFOURL); + adminGroup = config.getString(Keys.OIDC_ADMINGROUP); + } + +} diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 77aa9a635..ace4c36af 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -614,14 +614,14 @@ public final class Keys { /** * OIDC enable. */ - public static final ConfigKey OIDC_ENABLE = new BooleanConfigKey( + public static final ConfigKey OIDC_ENABLE = new BooleanConfigKey( "oidc.enable", List.of(KeyType.CONFIG)); /** * Force OIDC authentication. */ - public static final ConfigKey OIDC_FORCE = new BooleanConfigKey( + public static final ConfigKey OIDC_FORCE = new BooleanConfigKey( "oidc.force", List.of(KeyType.CONFIG)); -- cgit v1.2.3 From 7da68f71329f65d34a96bec26594c4b760384361 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 22:06:56 +0100 Subject: Add nimbus dependency --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index b27403861..ff5004c77 100644 --- a/build.gradle +++ b/build.gradle @@ -86,6 +86,8 @@ dependencies { implementation "com.hivemq:hivemq-mqtt-client:1.3.0" implementation "redis.clients:jedis:4.3.1" implementation "com.google.firebase:firebase-admin:9.1.1" + implementation "com.nimbusds:oauth2-oidc-sdk:10.7.1" + implementation "net.minidev:json-smart:2.4.10" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testImplementation "org.mockito:mockito-core:5.1.1" -- cgit v1.2.3 From f8339b4ca0ca7440854f759b32b821afe19f458b Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 22:07:42 +0100 Subject: Add user lookup method --- src/main/java/org/traccar/api/security/LoginService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 88bafcfb5..3d4f42b20 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -89,6 +89,19 @@ public class LoginService { return null; } + public User lookup(String email) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.All(), + new Condition.Equals("email", email))); + + if (user != null) { + checkUserEnabled(user); + return user; + } + + return null; + } + private void checkUserEnabled(User user) throws SecurityException { if (user == null) { throw new SecurityException("Unknown account"); -- cgit v1.2.3 From 92ebe0adba132bed5499bc1624620afeea34e347 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 22:41:36 +0100 Subject: Initial implementation --- src/main/java/org/traccar/MainModule.java | 5 +- .../org/traccar/api/resource/SessionResource.java | 25 +++ .../org/traccar/api/security/OpenIDProvider.java | 224 +++++++++++++++++++-- 3 files changed, 239 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 417844f50..7def97657 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -87,6 +87,7 @@ import org.traccar.storage.DatabaseStorage; import org.traccar.storage.MemoryStorage; import org.traccar.storage.Storage; import org.traccar.web.WebServer; +import org.traccar.api.security.LoginService; import org.traccar.api.security.OpenIDProvider; import javax.annotation.Nullable; @@ -173,9 +174,9 @@ public class MainModule extends AbstractModule { @Singleton @Provides - public static OpenIDProvider provideOpenIDProvider(Config config) { + public static OpenIDProvider provideOpenIDProvider(Config config, LoginService loginService, Storage storage) { if (config.getBoolean(Keys.OIDC_ENABLE)) { - return new OpenIDProvider(config); + return new OpenIDProvider(config, loginService, storage); } return null; } diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index ff84c135f..ca9f37667 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -17,6 +17,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; import org.traccar.api.security.LoginService; +import org.traccar.api.security.OpenIDProvider; import org.traccar.api.signature.TokenManager; import org.traccar.helper.DataConverter; import org.traccar.helper.LogAction; @@ -49,6 +50,7 @@ import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.Date; +import java.net.URI; @Path("session") @Produces(MediaType.APPLICATION_JSON) @@ -62,6 +64,9 @@ public class SessionResource extends BaseResource { @Inject private LoginService loginService; + @Inject + private OpenIDProvider openIdProvider; + @Inject private TokenManager tokenManager; @@ -160,4 +165,24 @@ public class SessionResource extends BaseResource { return tokenManager.generateToken(getUserId(), expiration); } + @PermitAll + @Path("openid/auth") + @GET + public Response openIdAuth() throws IOException { + return Response.seeOther( + openIdProvider.createAuthRequest() + ).build(); + } + + @PermitAll + @Path("openid/callback") + @GET + public Response requestToken() throws IOException, StorageException { + // Get full request URI + StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString()); + String queryString = request.getQueryString(); + String requestURI = requestURL.append('?').append(queryString).toString(); + + return openIdProvider.handleCallback(URI.create(requestURI), request); + } } diff --git a/src/main/java/org/traccar/api/security/OpenIDProvider.java b/src/main/java/org/traccar/api/security/OpenIDProvider.java index 4eaf9ac21..cd3fa4dde 100644 --- a/src/main/java/org/traccar/api/security/OpenIDProvider.java +++ b/src/main/java/org/traccar/api/security/OpenIDProvider.java @@ -15,30 +15,228 @@ */ package org.traccar.api.security; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.api.resource.SessionResource; import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Request; +import org.traccar.storage.query.Columns; +import org.traccar.helper.LogAction; +import org.traccar.helper.ServletHelper; -public class OpenIDProvider { +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Date; +import java.util.List; +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Response; +import com.google.inject.Inject; + +import com.nimbusds.oauth2.sdk.http.HTTPResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCode; +import com.nimbusds.oauth2.sdk.ResponseType; +import com.nimbusds.oauth2.sdk.Scope; +import com.nimbusds.oauth2.sdk.AuthorizationGrant; +import com.nimbusds.oauth2.sdk.TokenRequest; +import com.nimbusds.oauth2.sdk.TokenResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; +import com.nimbusds.oauth2.sdk.ParseException; +import com.nimbusds.oauth2.sdk.AuthorizationResponse; +import com.nimbusds.oauth2.sdk.auth.Secret; +import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; +import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; +import com.nimbusds.oauth2.sdk.token.BearerAccessToken; +import com.nimbusds.oauth2.sdk.id.State; +import com.nimbusds.oauth2.sdk.id.ClientID; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; +import com.nimbusds.openid.connect.sdk.Nonce; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; +import com.nimbusds.openid.connect.sdk.UserInfoResponse; +import com.nimbusds.openid.connect.sdk.UserInfoRequest; +import com.nimbusds.openid.connect.sdk.AuthenticationRequest; - private static final Logger LOGGER = LoggerFactory.getLogger(OpenIDProvider.class); +import com.nimbusds.openid.connect.sdk.claims.UserInfo; +public class OpenIDProvider { private final Boolean force; - private final String clientId; - private final String authUrl; - private final String tokenUrl; - private final String userInfoUrl; + private final ClientID clientId; + private final Secret clientSecret; + private URI callbackUrl; + private URI authUrl; + private URI tokenUrl; + private URI userInfoUrl; + private URI baseUrl; private final String adminGroup; - public OpenIDProvider(Config config) { + private Config config; + private LoginService loginService; + private Storage storage; + + @Inject + public OpenIDProvider(Config config, LoginService loginService, Storage storage) { force = config.getBoolean(Keys.OIDC_FORCE); - clientId = config.getString(Keys.OIDC_CLIENTID); - authUrl = config.getString(Keys.OIDC_AUTHURL); - tokenUrl = config.getString(Keys.OIDC_TOKENURL); - userInfoUrl = config.getString(Keys.OIDC_USERINFOURL); + clientId = new ClientID(config.getString(Keys.OIDC_CLIENTID)); + clientSecret = new Secret(config.getString(Keys.OIDC_CLIENTSECRET)); + + this.config = config; + this.storage = storage; + this.loginService = loginService; + + try { + callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); + authUrl = new URI(config.getString(Keys.OIDC_AUTHURL, "")); + tokenUrl = new URI(config.getString(Keys.OIDC_TOKENURL, "")); + userInfoUrl = new URI(config.getString(Keys.OIDC_USERINFOURL, "")); + baseUrl = new URI(config.getString(Keys.WEB_URL, "")); + } catch (URISyntaxException e) { + } + adminGroup = config.getString(Keys.OIDC_ADMINGROUP); } + public URI createAuthRequest() { + AuthenticationRequest request = new AuthenticationRequest.Builder( + new ResponseType("code"), + new Scope("openid", "profile", "email", "groups"), + this.clientId, + this.callbackUrl) + .endpointURI(this.authUrl) + .state(new State()) + .nonce(new Nonce()) + .build(); + + return request.toURI(); + } + + private OIDCTokenResponse getToken(AuthorizationCode code) { + // Credentials to authenticate us to the token endpoint + ClientAuthentication clientAuth = new ClientSecretBasic(this.clientId, this.clientSecret); + AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, this.callbackUrl); + + TokenRequest request = new TokenRequest(this.tokenUrl, clientAuth, codeGrant); + TokenResponse tokenResponse; + + try { + HTTPResponse tokenReq = request.toHTTPRequest().send(); + tokenResponse = OIDCTokenResponseParser.parse(tokenReq); + if (!tokenResponse.indicatesSuccess()) { + return null; + } + + return (OIDCTokenResponse) tokenResponse.toSuccessResponse(); + } catch (IOException e) { + return null; + } catch (ParseException e) { + return null; + } + } + + private AuthorizationCode parseCallback(URI requri) { + AuthorizationResponse response; + + try { + response = AuthorizationResponse.parse(requri); + } catch (ParseException e) { + return null; + } + + if (!response.indicatesSuccess()) { + return null; + } + + return response.toSuccessResponse().getAuthorizationCode(); + } + + private UserInfo getUserInfo(BearerAccessToken token) { + UserInfoResponse userInfoResponse; + + try { + HTTPResponse httpResponse = new UserInfoRequest(this.userInfoUrl, token) + .toHTTPRequest() + .send(); + + userInfoResponse = UserInfoResponse.parse(httpResponse); + } catch (IOException e) { + return null; + } catch (ParseException e) { + return null; + } + + if (!userInfoResponse.indicatesSuccess()) { + // User info request failed - usually from expiring + return null; + } + + return userInfoResponse.toSuccessResponse().getUserInfo(); + } + + private User createUser(String name, String email, Boolean administrator) throws StorageException { + User user = new User(); + + user.setName(name); + user.setEmail(email); + user.setFixedEmail(true); + user.setDeviceLimit(this.config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); + + int expirationDays = this.config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); + + if (expirationDays > 0) { + user.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L)); + } + + if (administrator) { + user.setAdministrator(true); + } + + user.setId(this.storage.addObject(user, new Request(new Columns.Exclude("id")))); + + return user; + } + + public Response handleCallback(URI requri, HttpServletRequest request) throws StorageException { + // Parse callback + AuthorizationCode authCode = this.parseCallback(requri); + + if (authCode == null) { + return Response.ok().entity("Callback parse fail").build(); + } + + // Get token from IDP + OIDCTokenResponse tokens = this.getToken(authCode); + + if (tokens == null) { + return Response.ok().entity("Token request failed").build(); + } + + BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); + + // Get user info from IDP + UserInfo idpUser = this.getUserInfo(bearerToken); + + if (idpUser == null) { + return Response.ok().entity("User info request failed").build(); + } + + String email = idpUser.getEmailAddress(); + String name = idpUser.getName(); + + // Check if user exists + User user = this.loginService.lookup(email); + + // If user does not exist, create one + if (user == null) { + List groups = idpUser.getStringListClaim("groups"); + Boolean administrator = groups.contains(this.adminGroup); + user = this.createUser(name, email, administrator); + } + + // Set user session and redirect to homepage + request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return Response.seeOther( + baseUrl).build(); + } } -- cgit v1.2.3 From b3840170a08a3ddbc070344c22e369aa08719a13 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 22:41:42 +0100 Subject: Swagger spec updates --- swagger.json | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/swagger.json b/swagger.json index 6c1e21d28..6a8bc91f6 100644 --- a/swagger.json +++ b/swagger.json @@ -1013,6 +1013,46 @@ } } }, + "/session/openid/auth": { + "get": { + "summary": "Fetch Session information", + "tags": [ + "Session" + ], + "parameters": [ + { + } + ], + "responses": { + "303": { + "description": "Redirect to OpenID Connect identity provider", + "content": { } + } + } + } + }, + "/session/openid/callback": { + "get": { + "summary": "OpenID Callback", + "tags": [ + "Session" + ], + "parameters": [ + { + } + ], + "responses": { + "303": { + "description": "Redirect to homepage", + "content": { } + }, + "404": { + "description": "Invalid callback", + "content": { } + } + } + } + }, "/users": { "get": { "summary": "Fetch a list of Users", -- cgit v1.2.3 From 21abf0f8479c48d8b826dd861f8c1227e6a00e25 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 22:53:34 +0100 Subject: Throw API error if oidc disabled --- src/main/java/org/traccar/api/resource/SessionResource.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index ca9f37667..515d7374a 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -169,6 +169,10 @@ public class SessionResource extends BaseResource { @Path("openid/auth") @GET public Response openIdAuth() throws IOException { + if (openIdProvider == null) { + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); + } + return Response.seeOther( openIdProvider.createAuthRequest() ).build(); @@ -178,6 +182,10 @@ public class SessionResource extends BaseResource { @Path("openid/callback") @GET public Response requestToken() throws IOException, StorageException { + if (openIdProvider == null) { + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); + } + // Get full request URI StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString()); String queryString = request.getQueryString(); -- cgit v1.2.3 From 040fa7c83b67b0c6541348c4ecd3979c7a80ebc5 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 1 Apr 2023 23:10:18 +0100 Subject: Expose OIDC state on /server endpoint --- .../java/org/traccar/api/security/OpenIDProvider.java | 2 +- src/main/java/org/traccar/model/Server.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/api/security/OpenIDProvider.java b/src/main/java/org/traccar/api/security/OpenIDProvider.java index cd3fa4dde..80d84dfbd 100644 --- a/src/main/java/org/traccar/api/security/OpenIDProvider.java +++ b/src/main/java/org/traccar/api/security/OpenIDProvider.java @@ -61,7 +61,7 @@ import com.nimbusds.openid.connect.sdk.AuthenticationRequest; import com.nimbusds.openid.connect.sdk.claims.UserInfo; public class OpenIDProvider { - private final Boolean force; + public final Boolean force; private final ClientID clientId; private final Secret clientSecret; private URI callbackUrl; diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index 73645721b..4c6e10b5e 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -16,13 +16,16 @@ package org.traccar.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import org.traccar.Main; +import org.traccar.api.security.OpenIDProvider; import org.traccar.storage.QueryIgnore; import org.traccar.storage.StorageName; @StorageName("tc_servers") @JsonIgnoreProperties(ignoreUnknown = true) public class Server extends ExtendedModel implements UserRestrictions { - + private boolean registration; public boolean getRegistration() { @@ -261,4 +264,15 @@ public class Server extends ExtendedModel implements UserRestrictions { this.newServer = newServer; } + @QueryIgnore + public boolean getOidcEnabled() { + OpenIDProvider oidc = Main.getInjector().getInstance(OpenIDProvider.class); + return oidc != null; + } + + @QueryIgnore + public boolean getOidcForce() { + OpenIDProvider oidc = Main.getInjector().getInstance(OpenIDProvider.class); + return oidc != null && oidc.force; + } } -- cgit v1.2.3 From 2cc1cb3c7530fdabb750a9e0b5cc26e3e2286185 Mon Sep 17 00:00:00 2001 From: Dan Date: Sun, 2 Apr 2023 13:51:46 +0100 Subject: Add better error handling --- .../java/org/traccar/api/security/OpenIDProvider.java | 15 +++++++++------ swagger.json | 16 ++++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/api/security/OpenIDProvider.java b/src/main/java/org/traccar/api/security/OpenIDProvider.java index 80d84dfbd..1e18fde43 100644 --- a/src/main/java/org/traccar/api/security/OpenIDProvider.java +++ b/src/main/java/org/traccar/api/security/OpenIDProvider.java @@ -32,6 +32,7 @@ import java.util.Date; import java.util.List; import java.io.IOException; import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import com.google.inject.Inject; @@ -43,6 +44,7 @@ import com.nimbusds.oauth2.sdk.AuthorizationGrant; import com.nimbusds.oauth2.sdk.TokenRequest; import com.nimbusds.oauth2.sdk.TokenResponse; import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; +import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse; import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.AuthorizationResponse; import com.nimbusds.oauth2.sdk.auth.Secret; @@ -134,7 +136,7 @@ public class OpenIDProvider { } } - private AuthorizationCode parseCallback(URI requri) { + private AuthorizationCode parseCallback(URI requri) throws WebApplicationException { AuthorizationResponse response; try { @@ -144,7 +146,8 @@ public class OpenIDProvider { } if (!response.indicatesSuccess()) { - return null; + AuthorizationErrorResponse error = response.toErrorResponse(); + throw new WebApplicationException(Response.status(403).entity(error.getErrorObject().getDescription()).build()); } return response.toSuccessResponse().getAuthorizationCode(); @@ -196,19 +199,19 @@ public class OpenIDProvider { return user; } - public Response handleCallback(URI requri, HttpServletRequest request) throws StorageException { + public Response handleCallback(URI requri, HttpServletRequest request) throws StorageException, WebApplicationException { // Parse callback AuthorizationCode authCode = this.parseCallback(requri); if (authCode == null) { - return Response.ok().entity("Callback parse fail").build(); + return Response.status(403).entity( "Invalid OpenID Connect callback.").build(); } // Get token from IDP OIDCTokenResponse tokens = this.getToken(authCode); if (tokens == null) { - return Response.ok().entity("Token request failed").build(); + return Response.status(403).entity("Unable to authenticate with the OpenID Connect provider. Please try again.").build(); } BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); @@ -217,7 +220,7 @@ public class OpenIDProvider { UserInfo idpUser = this.getUserInfo(bearerToken); if (idpUser == null) { - return Response.ok().entity("User info request failed").build(); + return Response.status(500).entity("Failed to access OpenID Connect user info endpoint. Please contact your administrator.").build(); } String email = idpUser.getEmailAddress(); diff --git a/swagger.json b/swagger.json index 6a8bc91f6..8968db4eb 100644 --- a/swagger.json +++ b/swagger.json @@ -1027,6 +1027,10 @@ "303": { "description": "Redirect to OpenID Connect identity provider", "content": { } + }, + "404": { + "description": "OpenID Connect disabled", + "content": { } } } } @@ -1043,11 +1047,19 @@ ], "responses": { "303": { - "description": "Redirect to homepage", + "description": "Successful authentication, redirect to homepage", + "content": { } + }, + "403": { + "description": "Invalid callback or negative response from identity provider", "content": { } }, "404": { - "description": "Invalid callback", + "description": "OpenID Connect disabled", + "content": { } + }, + "500": { + "description": "Other OpenID Connect error", "content": { } } } -- cgit v1.2.3 From e1dd95a96758000b085cbf5e2ac9c03dc46f3060 Mon Sep 17 00:00:00 2001 From: Dan Raper Date: Sun, 2 Apr 2023 14:42:03 +0100 Subject: Update server swagger schema --- swagger.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/swagger.json b/swagger.json index 8968db4eb..d3a83ba76 100644 --- a/swagger.json +++ b/swagger.json @@ -2821,6 +2821,12 @@ "coordinateFormat": { "type": "string" }, + "oidcEnabled": { + "type": "boolean" + }, + "oidcForce": { + "type": "boolean" + }, "attributes": { "type": "object", "properties": {} @@ -3533,4 +3539,4 @@ } } } -} \ No newline at end of file +} -- cgit v1.2.3 From faf5567add4cf343cc38b3c7dcb297c7cbed88bc Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 12:12:38 +0100 Subject: First pass --- src/main/java/org/traccar/MainModule.java | 8 +- .../org/traccar/api/resource/ServerResource.java | 7 + .../org/traccar/api/resource/SessionResource.java | 26 +-- .../org/traccar/api/security/LoginService.java | 17 +- .../org/traccar/api/security/OpenIDProvider.java | 245 --------------------- src/main/java/org/traccar/config/Keys.java | 68 +++--- .../java/org/traccar/database/OpenIdProvider.java | 183 +++++++++++++++ src/main/java/org/traccar/model/Server.java | 28 ++- 8 files changed, 270 insertions(+), 312 deletions(-) delete mode 100644 src/main/java/org/traccar/api/security/OpenIDProvider.java create mode 100644 src/main/java/org/traccar/database/OpenIdProvider.java diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 7def97657..7b06b4840 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -33,6 +33,7 @@ import org.traccar.broadcast.NullBroadcastService; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.LdapProvider; +import org.traccar.database.OpenIdProvider; import org.traccar.database.StatisticsManager; import org.traccar.forward.EventForwarder; import org.traccar.forward.EventForwarderJson; @@ -88,7 +89,6 @@ import org.traccar.storage.MemoryStorage; import org.traccar.storage.Storage; import org.traccar.web.WebServer; import org.traccar.api.security.LoginService; -import org.traccar.api.security.OpenIDProvider; import javax.annotation.Nullable; import javax.inject.Singleton; @@ -174,9 +174,9 @@ public class MainModule extends AbstractModule { @Singleton @Provides - public static OpenIDProvider provideOpenIDProvider(Config config, LoginService loginService, Storage storage) { - if (config.getBoolean(Keys.OIDC_ENABLE)) { - return new OpenIDProvider(config, loginService, storage); + public static OpenIdProvider provideOpenIDProvider(Config config, LoginService loginService) { + if (config.hasKey(Keys.OPENID_CLIENTID)) { + return new OpenIdProvider(config, loginService); } return null; } diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 4b7ee9189..9b4d82a66 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -16,6 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; +import org.traccar.database.OpenIdProvider; import org.traccar.helper.model.UserUtil; import org.traccar.mail.MailManager; import org.traccar.geocoder.Geocoder; @@ -55,6 +56,10 @@ public class ServerResource extends BaseResource { @Inject private MailManager mailManager; + @Inject + @Nullable + private OpenIdProvider openIdProvider; + @Inject @Nullable private Geocoder geocoder; @@ -65,6 +70,8 @@ public class ServerResource extends BaseResource { Server server = storage.getObject(Server.class, new Request(new Columns.All())); server.setEmailEnabled(mailManager.getEmailEnabled()); server.setGeocoderEnabled(geocoder != null); + server.setOpenIdEnabled(openIdProvider != null); + server.setOpenIdForce(openIdProvider != null && openIdProvider.force); User user = permissionsService.getUser(getUserId()); if (user != null) { if (user.getAdministrator()) { diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 515d7374a..3de20b8c7 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -17,8 +17,8 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; import org.traccar.api.security.LoginService; -import org.traccar.api.security.OpenIDProvider; import org.traccar.api.signature.TokenManager; +import org.traccar.database.OpenIdProvider; import org.traccar.helper.DataConverter; import org.traccar.helper.LogAction; import org.traccar.helper.ServletHelper; @@ -28,6 +28,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; +import com.nimbusds.oauth2.sdk.ParseException; import javax.annotation.security.PermitAll; import javax.inject.Inject; import javax.servlet.http.Cookie; @@ -65,7 +66,7 @@ public class SessionResource extends BaseResource { private LoginService loginService; @Inject - private OpenIDProvider openIdProvider; + private OpenIdProvider openIdProvider; @Inject private TokenManager tokenManager; @@ -169,28 +170,17 @@ public class SessionResource extends BaseResource { @Path("openid/auth") @GET public Response openIdAuth() throws IOException { - if (openIdProvider == null) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); - } - - return Response.seeOther( - openIdProvider.createAuthRequest() - ).build(); + return Response.seeOther(openIdProvider.createAuthUri()).build(); } @PermitAll @Path("openid/callback") @GET - public Response requestToken() throws IOException, StorageException { - if (openIdProvider == null) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); - } - - // Get full request URI - StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString()); + public Response requestToken() throws IOException, StorageException, ParseException { + StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString()); String queryString = request.getQueryString(); - String requestURI = requestURL.append('?').append(queryString).toString(); + String requestUri = requestUrl.append('?').append(queryString).toString(); - return openIdProvider.handleCallback(URI.create(requestURI), request); + return openIdProvider.handleCallback(URI.create(requestUri), request); } } diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 3d4f42b20..7b51667c8 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -89,17 +89,24 @@ public class LoginService { return null; } - public User lookup(String email) throws StorageException { + public User login(String email, String name, Boolean administrator) throws StorageException { User user = storage.getObject(User.class, new Request( - new Columns.All(), - new Condition.Equals("email", email))); + new Columns.All(), + new Condition.Equals("email", email))); if (user != null) { checkUserEnabled(user); return user; + } else { + user = new User(); + user.setName(name); + user.setEmail(email); + user.setFixedEmail(true); + user.setAdministrator(administrator); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + checkUserEnabled(user); + return user; } - - return null; } private void checkUserEnabled(User user) throws SecurityException { diff --git a/src/main/java/org/traccar/api/security/OpenIDProvider.java b/src/main/java/org/traccar/api/security/OpenIDProvider.java deleted file mode 100644 index 1e18fde43..000000000 --- a/src/main/java/org/traccar/api/security/OpenIDProvider.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2017 - 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.api.security; - -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.api.resource.SessionResource; -import org.traccar.model.User; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Request; -import org.traccar.storage.query.Columns; -import org.traccar.helper.LogAction; -import org.traccar.helper.ServletHelper; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Date; -import java.util.List; -import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import com.google.inject.Inject; - -import com.nimbusds.oauth2.sdk.http.HTTPResponse; -import com.nimbusds.oauth2.sdk.AuthorizationCode; -import com.nimbusds.oauth2.sdk.ResponseType; -import com.nimbusds.oauth2.sdk.Scope; -import com.nimbusds.oauth2.sdk.AuthorizationGrant; -import com.nimbusds.oauth2.sdk.TokenRequest; -import com.nimbusds.oauth2.sdk.TokenResponse; -import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; -import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse; -import com.nimbusds.oauth2.sdk.ParseException; -import com.nimbusds.oauth2.sdk.AuthorizationResponse; -import com.nimbusds.oauth2.sdk.auth.Secret; -import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; -import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; -import com.nimbusds.oauth2.sdk.token.BearerAccessToken; -import com.nimbusds.oauth2.sdk.id.State; -import com.nimbusds.oauth2.sdk.id.ClientID; -import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; -import com.nimbusds.openid.connect.sdk.Nonce; -import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; -import com.nimbusds.openid.connect.sdk.UserInfoResponse; -import com.nimbusds.openid.connect.sdk.UserInfoRequest; -import com.nimbusds.openid.connect.sdk.AuthenticationRequest; - -import com.nimbusds.openid.connect.sdk.claims.UserInfo; - -public class OpenIDProvider { - public final Boolean force; - private final ClientID clientId; - private final Secret clientSecret; - private URI callbackUrl; - private URI authUrl; - private URI tokenUrl; - private URI userInfoUrl; - private URI baseUrl; - private final String adminGroup; - - private Config config; - private LoginService loginService; - private Storage storage; - - @Inject - public OpenIDProvider(Config config, LoginService loginService, Storage storage) { - force = config.getBoolean(Keys.OIDC_FORCE); - clientId = new ClientID(config.getString(Keys.OIDC_CLIENTID)); - clientSecret = new Secret(config.getString(Keys.OIDC_CLIENTSECRET)); - - this.config = config; - this.storage = storage; - this.loginService = loginService; - - try { - callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); - authUrl = new URI(config.getString(Keys.OIDC_AUTHURL, "")); - tokenUrl = new URI(config.getString(Keys.OIDC_TOKENURL, "")); - userInfoUrl = new URI(config.getString(Keys.OIDC_USERINFOURL, "")); - baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - } catch (URISyntaxException e) { - } - - adminGroup = config.getString(Keys.OIDC_ADMINGROUP); - } - - public URI createAuthRequest() { - AuthenticationRequest request = new AuthenticationRequest.Builder( - new ResponseType("code"), - new Scope("openid", "profile", "email", "groups"), - this.clientId, - this.callbackUrl) - .endpointURI(this.authUrl) - .state(new State()) - .nonce(new Nonce()) - .build(); - - return request.toURI(); - } - - private OIDCTokenResponse getToken(AuthorizationCode code) { - // Credentials to authenticate us to the token endpoint - ClientAuthentication clientAuth = new ClientSecretBasic(this.clientId, this.clientSecret); - AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, this.callbackUrl); - - TokenRequest request = new TokenRequest(this.tokenUrl, clientAuth, codeGrant); - TokenResponse tokenResponse; - - try { - HTTPResponse tokenReq = request.toHTTPRequest().send(); - tokenResponse = OIDCTokenResponseParser.parse(tokenReq); - if (!tokenResponse.indicatesSuccess()) { - return null; - } - - return (OIDCTokenResponse) tokenResponse.toSuccessResponse(); - } catch (IOException e) { - return null; - } catch (ParseException e) { - return null; - } - } - - private AuthorizationCode parseCallback(URI requri) throws WebApplicationException { - AuthorizationResponse response; - - try { - response = AuthorizationResponse.parse(requri); - } catch (ParseException e) { - return null; - } - - if (!response.indicatesSuccess()) { - AuthorizationErrorResponse error = response.toErrorResponse(); - throw new WebApplicationException(Response.status(403).entity(error.getErrorObject().getDescription()).build()); - } - - return response.toSuccessResponse().getAuthorizationCode(); - } - - private UserInfo getUserInfo(BearerAccessToken token) { - UserInfoResponse userInfoResponse; - - try { - HTTPResponse httpResponse = new UserInfoRequest(this.userInfoUrl, token) - .toHTTPRequest() - .send(); - - userInfoResponse = UserInfoResponse.parse(httpResponse); - } catch (IOException e) { - return null; - } catch (ParseException e) { - return null; - } - - if (!userInfoResponse.indicatesSuccess()) { - // User info request failed - usually from expiring - return null; - } - - return userInfoResponse.toSuccessResponse().getUserInfo(); - } - - private User createUser(String name, String email, Boolean administrator) throws StorageException { - User user = new User(); - - user.setName(name); - user.setEmail(email); - user.setFixedEmail(true); - user.setDeviceLimit(this.config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); - - int expirationDays = this.config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); - - if (expirationDays > 0) { - user.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L)); - } - - if (administrator) { - user.setAdministrator(true); - } - - user.setId(this.storage.addObject(user, new Request(new Columns.Exclude("id")))); - - return user; - } - - public Response handleCallback(URI requri, HttpServletRequest request) throws StorageException, WebApplicationException { - // Parse callback - AuthorizationCode authCode = this.parseCallback(requri); - - if (authCode == null) { - return Response.status(403).entity( "Invalid OpenID Connect callback.").build(); - } - - // Get token from IDP - OIDCTokenResponse tokens = this.getToken(authCode); - - if (tokens == null) { - return Response.status(403).entity("Unable to authenticate with the OpenID Connect provider. Please try again.").build(); - } - - BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); - - // Get user info from IDP - UserInfo idpUser = this.getUserInfo(bearerToken); - - if (idpUser == null) { - return Response.status(500).entity("Failed to access OpenID Connect user info endpoint. Please contact your administrator.").build(); - } - - String email = idpUser.getEmailAddress(); - String name = idpUser.getName(); - - // Check if user exists - User user = this.loginService.lookup(email); - - // If user does not exist, create one - if (user == null) { - List groups = idpUser.getStringListClaim("groups"); - Boolean administrator = groups.contains(this.adminGroup); - user = this.createUser(name, email, administrator); - } - - // Set user session and redirect to homepage - request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return Response.seeOther( - baseUrl).build(); - } -} diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index ace4c36af..a666667d4 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -610,61 +610,67 @@ public final class Keys { "ldap.adminGroup", List.of(KeyType.CONFIG)); - /** - * OIDC enable. + * Force OpenID Connect authentication. When enabled, the Traccar login page will be skipped + * and users are redirected to the OpenID Connect provider. */ - public static final ConfigKey OIDC_ENABLE = new BooleanConfigKey( - "oidc.enable", + public static final ConfigKey OPENID_FORCE = new BooleanConfigKey( + "openid.force", List.of(KeyType.CONFIG)); /** - * Force OIDC authentication. + * OpenID Connect Client ID. + * This is a unique ID assigned to each application you register with your identity provider. + * Required to enable SSO. */ - public static final ConfigKey OIDC_FORCE = new BooleanConfigKey( - "oidc.force", + public static final ConfigKey OPENID_CLIENTID = new StringConfigKey( + "openid.clientId", List.of(KeyType.CONFIG)); /** - * OIDC Client ID. + * OpenID Connect Client Secret. + * This is a secret assigned to each application you register with your identity provider. + * Required to enable SSO. */ - public static final ConfigKey OIDC_CLIENTID = new StringConfigKey( - "oidc.clientId", + public static final ConfigKey OPENID_CLIENTSECRET = new StringConfigKey( + "openid.clientSecret", List.of(KeyType.CONFIG)); /** - * OIDC Client Secret. + * OpenID Connect Authorization URL. + * This can usually be found in the documentation of your identity provider or by using the well-known + * configuration endpoint, eg. https://auth.example.com//.well-known/openid-configuration + * Required to enable SSO. */ - public static final ConfigKey OIDC_CLIENTSECRET = new StringConfigKey( - "oidc.clientSecret", + public static final ConfigKey OPENID_AUTHURL = new StringConfigKey( + "openid.authUrl", List.of(KeyType.CONFIG)); - /** - * OIDC Authorization URL. + * OpenID Connect Token URL. + * This can be found in the same ways at openid.authUrl. + * Required to enable SSO. */ - public static final ConfigKey OIDC_AUTHURL = new StringConfigKey( - "oidc.authUrl", - List.of(KeyType.CONFIG)); - /** - * OIDC Token URL. - */ - public static final ConfigKey OIDC_TOKENURL = new StringConfigKey( - "oidc.tokenUrl", + public static final ConfigKey OPENID_TOKENURL = new StringConfigKey( + "openid.tokenUrl", List.of(KeyType.CONFIG)); /** - * OIDC User Info URL. + * OpenID Connect User Info URL. + * This can be found in the same ways at openid.authUrl. + * Required to enable SSO. */ - public static final ConfigKey OIDC_USERINFOURL = new StringConfigKey( - "oidc.userInfoUrl", + public static final ConfigKey OPENID_USERINFOURL = new StringConfigKey( + "openid.userInfoUrl", List.of(KeyType.CONFIG)); /** - * OIDC group to grant admin access. + * OpenID Connect group to grant admin access. + * Defaults to admins. */ - public static final ConfigKey OIDC_ADMINGROUP = new StringConfigKey( - "oidc.adminGroup", - List.of(KeyType.CONFIG)); + public static final ConfigKey OPENID_ADMINGROUP = new StringConfigKey( + "openid.adminGroup", + List.of(KeyType.CONFIG), + "admins"); /** * If no data is reported by a device for the given amount of time, status changes from online to unknown. Value is @@ -1629,7 +1635,7 @@ public final class Keys { List.of(KeyType.CONFIG)); /** - * Public URL for the web app. Used for notification and report link. + * Public URL for the web app. Used for notification, report link and OpenID Connect. * If not provided, Traccar will attempt to get a URL from the server IP address, but it might be a local address. */ public static final ConfigKey WEB_URL = new StringConfigKey( diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java new file mode 100644 index 000000000..fc1409d14 --- /dev/null +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -0,0 +1,183 @@ +/* + * Copyright 2023 Daniel Raper (me@danr.uk) + * + * 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.database; + +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.api.resource.SessionResource; +import org.traccar.api.security.LoginService; +import org.traccar.model.User; +import org.traccar.storage.StorageException; +import org.traccar.helper.LogAction; +import org.traccar.helper.ServletHelper; + +import java.net.URI; +import java.net.URISyntaxException; +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import com.google.inject.Inject; + +import com.nimbusds.oauth2.sdk.http.HTTPResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCode; +import com.nimbusds.oauth2.sdk.ResponseType; +import com.nimbusds.oauth2.sdk.Scope; +import com.nimbusds.oauth2.sdk.AuthorizationGrant; +import com.nimbusds.oauth2.sdk.TokenRequest; +import com.nimbusds.oauth2.sdk.TokenResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; +import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse; +import com.nimbusds.oauth2.sdk.ParseException; +import com.nimbusds.oauth2.sdk.AuthorizationResponse; +import com.nimbusds.oauth2.sdk.auth.Secret; +import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; +import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; +import com.nimbusds.oauth2.sdk.token.BearerAccessToken; +import com.nimbusds.oauth2.sdk.id.State; +import com.nimbusds.oauth2.sdk.id.ClientID; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; +import com.nimbusds.openid.connect.sdk.Nonce; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; +import com.nimbusds.openid.connect.sdk.UserInfoResponse; +import com.nimbusds.openid.connect.sdk.UserInfoRequest; +import com.nimbusds.openid.connect.sdk.AuthenticationRequest; + +import com.nimbusds.openid.connect.sdk.claims.UserInfo; + +public class OpenIdProvider { + public final Boolean force; + private final ClientID clientId; + private final Secret clientSecret; + private URI callbackUrl; + private URI authUrl; + private URI tokenUrl; + private URI userInfoUrl; + private URI baseUrl; + private final String adminGroup; + + private LoginService loginService; + + @Inject + public OpenIdProvider(Config config, LoginService loginService) { + force = config.getBoolean(Keys.OPENID_FORCE); + clientId = new ClientID(config.getString(Keys.OPENID_CLIENTID)); + clientSecret = new Secret(config.getString(Keys.OPENID_CLIENTSECRET)); + + this.loginService = loginService; + + try { + callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); + authUrl = new URI(config.getString(Keys.OPENID_AUTHURL, "")); + tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); + userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); + baseUrl = new URI(config.getString(Keys.WEB_URL, "")); + } catch (URISyntaxException e) { + } + + adminGroup = config.getString(Keys.OPENID_ADMINGROUP); + } + + public URI createAuthUri() { + AuthenticationRequest request = new AuthenticationRequest.Builder( + new ResponseType("code"), + new Scope("openid", "profile", "email", "groups"), + clientId, + callbackUrl) + .endpointURI(authUrl) + .state(new State()) + .nonce(new Nonce()) + .build(); + + return request.toURI(); + } + + private OIDCTokenResponse getToken(AuthorizationCode code) { + // Credentials to authenticate us to the token endpoint + ClientAuthentication clientAuth = new ClientSecretBasic(clientId, clientSecret); + AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); + + TokenRequest request = new TokenRequest(tokenUrl, clientAuth, codeGrant); + TokenResponse tokenResponse; + + try { + HTTPResponse tokenReq = request.toHTTPRequest().send(); + tokenResponse = OIDCTokenResponseParser.parse(tokenReq); + if (!tokenResponse.indicatesSuccess()) { + return null; + } + + return (OIDCTokenResponse) tokenResponse.toSuccessResponse(); + } catch (IOException e) { + return null; + } catch (ParseException e) { + return null; + } + } + + private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException { + UserInfoResponse userInfoResponse; + + HTTPResponse httpResponse = new UserInfoRequest(userInfoUrl, token) + .toHTTPRequest() + .send(); + + userInfoResponse = UserInfoResponse.parse(httpResponse); + + if (!userInfoResponse.indicatesSuccess()) { + // User info request failed - usually from expiring + return null; + } + + return userInfoResponse.toSuccessResponse().getUserInfo(); + } + + public Response handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, WebApplicationException { + AuthorizationResponse response = AuthorizationResponse.parse(requestUri); + + if (!response.indicatesSuccess()) { + AuthorizationErrorResponse error = response.toErrorResponse(); + throw new WebApplicationException(Response.status(403).entity(error.getErrorObject().getDescription()).build()); + } + + AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); + + if (authCode == null) { + return Response.status(403).entity( "Invalid OpenID Connect callback.").build(); + } + + OIDCTokenResponse tokens = getToken(authCode); + + if (tokens == null) { + return Response.status(403).entity("Unable to authenticate with the OpenID Connect provider. Please try again.").build(); + } + + BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); + + UserInfo userInfo = getUserInfo(bearerToken); + + if (userInfo == null) { + return Response.status(500).entity("Failed to access OpenID Connect user info endpoint. Please contact your administrator.").build(); + } + + User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), userInfo.getStringListClaim("groups").contains(adminGroup)); + + request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return Response.seeOther( + baseUrl).build(); + } +} diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index 4c6e10b5e..b790ca472 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -17,15 +17,13 @@ package org.traccar.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.traccar.Main; -import org.traccar.api.security.OpenIDProvider; import org.traccar.storage.QueryIgnore; import org.traccar.storage.StorageName; @StorageName("tc_servers") @JsonIgnoreProperties(ignoreUnknown = true) public class Server extends ExtendedModel implements UserRestrictions { - + private boolean registration; public boolean getRegistration() { @@ -264,15 +262,27 @@ public class Server extends ExtendedModel implements UserRestrictions { this.newServer = newServer; } + private boolean openIdEnabled; + + @QueryIgnore + public boolean getOpenIdEnabled() { + return openIdEnabled; + } + + @QueryIgnore + public void setOpenIdEnabled(boolean openIdEnabled) { + this.openIdEnabled = openIdEnabled; + } + + private boolean openIdForce; + @QueryIgnore - public boolean getOidcEnabled() { - OpenIDProvider oidc = Main.getInjector().getInstance(OpenIDProvider.class); - return oidc != null; + public boolean getOpenIdForce() { + return openIdForce; } @QueryIgnore - public boolean getOidcForce() { - OpenIDProvider oidc = Main.getInjector().getInstance(OpenIDProvider.class); - return oidc != null && oidc.force; + public void setOpenIdForce(boolean openIdForce) { + this.openIdForce = openIdForce; } } -- cgit v1.2.3 From 0fc695a4c1a09ef9d33ea2fd0658f6dece989381 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 12:58:26 +0100 Subject: Second pass --- build.gradle | 1 - .../org/traccar/api/resource/SessionResource.java | 4 +- .../java/org/traccar/database/OpenIdProvider.java | 75 +++++++++------------- traccar-web | 2 +- 4 files changed, 34 insertions(+), 48 deletions(-) diff --git a/build.gradle b/build.gradle index ff5004c77..c29f3ba26 100644 --- a/build.gradle +++ b/build.gradle @@ -87,7 +87,6 @@ dependencies { implementation "redis.clients:jedis:4.3.1" implementation "com.google.firebase:firebase-admin:9.1.1" implementation "com.nimbusds:oauth2-oidc-sdk:10.7.1" - implementation "net.minidev:json-smart:2.4.10" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testImplementation "org.mockito:mockito-core:5.1.1" diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 3de20b8c7..a20e5f100 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -176,11 +176,11 @@ public class SessionResource extends BaseResource { @PermitAll @Path("openid/callback") @GET - public Response requestToken() throws IOException, StorageException, ParseException { + public Response requestToken() throws IOException, StorageException, ParseException, GeneralSecurityException { StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString()); String queryString = request.getQueryString(); String requestUri = requestUrl.append('?').append(queryString).toString(); - return openIdProvider.handleCallback(URI.create(requestUri), request); + return Response.seeOther(openIdProvider.handleCallback(URI.create(requestUri), request)).build(); } } diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index fc1409d14..6f44d0e80 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -26,11 +26,12 @@ import org.traccar.helper.ServletHelper; import java.net.URI; import java.net.URISyntaxException; +import java.security.GeneralSecurityException; import java.io.IOException; import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; import com.google.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.AuthorizationCode; @@ -40,7 +41,6 @@ import com.nimbusds.oauth2.sdk.AuthorizationGrant; import com.nimbusds.oauth2.sdk.TokenRequest; import com.nimbusds.oauth2.sdk.TokenResponse; import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; -import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse; import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.AuthorizationResponse; import com.nimbusds.oauth2.sdk.auth.Secret; @@ -59,9 +59,11 @@ import com.nimbusds.openid.connect.sdk.AuthenticationRequest; import com.nimbusds.openid.connect.sdk.claims.UserInfo; public class OpenIdProvider { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdProvider.class); + public final Boolean force; private final ClientID clientId; - private final Secret clientSecret; + private final ClientAuthentication clientAuth; private URI callbackUrl; private URI authUrl; private URI tokenUrl; @@ -72,12 +74,12 @@ public class OpenIdProvider { private LoginService loginService; @Inject - public OpenIdProvider(Config config, LoginService loginService) { + public OpenIdProvider(Config config, LoginService loginService) { + this.loginService = loginService; + force = config.getBoolean(Keys.OPENID_FORCE); clientId = new ClientID(config.getString(Keys.OPENID_CLIENTID)); - clientSecret = new Secret(config.getString(Keys.OPENID_CLIENTSECRET)); - - this.loginService = loginService; + clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENTSECRET))); try { callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); @@ -85,7 +87,8 @@ public class OpenIdProvider { tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - } catch (URISyntaxException e) { + } catch(URISyntaxException error) { + LOGGER.error("Invalid URIs provided in OpenID configuration"); } adminGroup = config.getString(Keys.OPENID_ADMINGROUP); @@ -105,30 +108,21 @@ public class OpenIdProvider { return request.toURI(); } - private OIDCTokenResponse getToken(AuthorizationCode code) { - // Credentials to authenticate us to the token endpoint - ClientAuthentication clientAuth = new ClientSecretBasic(clientId, clientSecret); + private OIDCTokenResponse getToken(AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); + TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); - TokenRequest request = new TokenRequest(tokenUrl, clientAuth, codeGrant); - TokenResponse tokenResponse; - - try { - HTTPResponse tokenReq = request.toHTTPRequest().send(); - tokenResponse = OIDCTokenResponseParser.parse(tokenReq); - if (!tokenResponse.indicatesSuccess()) { - return null; - } - - return (OIDCTokenResponse) tokenResponse.toSuccessResponse(); - } catch (IOException e) { - return null; - } catch (ParseException e) { - return null; + HTTPResponse tokenReq = tokenRequest.toHTTPRequest().send(); + TokenResponse tokenResponse = OIDCTokenResponseParser.parse(tokenReq); + if (!tokenResponse.indicatesSuccess()) { + LOGGER.warn("Invalid authorization code provided to OpenID callback"); + throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); } + + return (OIDCTokenResponse) tokenResponse.toSuccessResponse(); } - private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException { + private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException { UserInfoResponse userInfoResponse; HTTPResponse httpResponse = new UserInfoRequest(userInfoUrl, token) @@ -138,46 +132,39 @@ public class OpenIdProvider { userInfoResponse = UserInfoResponse.parse(httpResponse); if (!userInfoResponse.indicatesSuccess()) { - // User info request failed - usually from expiring - return null; + LOGGER.error("Failed to access OpenID user info endpoint"); + throw new GeneralSecurityException("Failed to access OpenID Connect user info endpoint. Please contact your administrator."); } return userInfoResponse.toSuccessResponse().getUserInfo(); } - public Response handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, WebApplicationException { + public URI handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, GeneralSecurityException { AuthorizationResponse response = AuthorizationResponse.parse(requestUri); if (!response.indicatesSuccess()) { - AuthorizationErrorResponse error = response.toErrorResponse(); - throw new WebApplicationException(Response.status(403).entity(error.getErrorObject().getDescription()).build()); + LOGGER.warn("Callback received error response from OpenID identity provider"); + throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); } AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); if (authCode == null) { - return Response.status(403).entity( "Invalid OpenID Connect callback.").build(); + LOGGER.warn("Malformed OpenID callback"); + throw new GeneralSecurityException( "Malformed OpenID callback."); } OIDCTokenResponse tokens = getToken(authCode); - if (tokens == null) { - return Response.status(403).entity("Unable to authenticate with the OpenID Connect provider. Please try again.").build(); - } - BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); UserInfo userInfo = getUserInfo(bearerToken); - if (userInfo == null) { - return Response.status(500).entity("Failed to access OpenID Connect user info endpoint. Please contact your administrator.").build(); - } - User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), userInfo.getStringListClaim("groups").contains(adminGroup)); request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return Response.seeOther( - baseUrl).build(); + + return baseUrl; } } diff --git a/traccar-web b/traccar-web index 091d10531..506dd66b7 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 091d10531a59216c5f0a812609742e097c68ff2c +Subproject commit 506dd66b793803a24a2872e242482f263087df52 -- cgit v1.2.3 From 1019243f07cdd026b573af593323830e9ebd0333 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 17:17:48 +0100 Subject: Further review changes --- .../org/traccar/api/resource/SessionResource.java | 374 +- .../java/org/traccar/database/OpenIdProvider.java | 333 +- swagger.json | 7068 ++++++++++---------- 3 files changed, 3877 insertions(+), 3898 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index a20e5f100..8240a8a6f 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -1,186 +1,188 @@ -/* - * Copyright 2015 - 2022 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.api.resource; - -import org.traccar.api.BaseResource; -import org.traccar.api.security.LoginService; -import org.traccar.api.signature.TokenManager; -import org.traccar.database.OpenIdProvider; -import org.traccar.helper.DataConverter; -import org.traccar.helper.LogAction; -import org.traccar.helper.ServletHelper; -import org.traccar.model.User; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import com.nimbusds.oauth2.sdk.ParseException; -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.io.IOException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.util.Date; -import java.net.URI; - -@Path("session") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_FORM_URLENCODED) -public class SessionResource extends BaseResource { - - public static final String USER_ID_KEY = "userId"; - public static final String USER_COOKIE_KEY = "user"; - public static final String PASS_COOKIE_KEY = "password"; - - @Inject - private LoginService loginService; - - @Inject - private OpenIdProvider openIdProvider; - - @Inject - private TokenManager tokenManager; - - @Context - private HttpServletRequest request; - - @PermitAll - @GET - public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException { - - if (token != null) { - User user = loginService.login(token); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } - } - - Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); - if (userId == null) { - - Cookie[] cookies = request.getCookies(); - String email = null, password = null; - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals(USER_COOKIE_KEY)) { - byte[] emailBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); - email = new String(emailBytes, StandardCharsets.UTF_8); - } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { - byte[] passwordBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); - password = new String(passwordBytes, StandardCharsets.UTF_8); - } - } - } - if (email != null && password != null) { - User user = loginService.login(email, password); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } - } - - } else { - - User user = permissionsService.getUser(userId); - if (user != null) { - return user; - } - - } - - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); - } - - @Path("{id}") - @GET - public User get(@PathParam("id") long userId) throws StorageException { - permissionsService.checkUser(getUserId(), userId); - User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", userId))); - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } - - @PermitAll - @POST - public User add( - @FormParam("email") String email, @FormParam("password") String password) throws StorageException { - User user = loginService.login(email, password); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } else { - LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request)); - throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); - } - } - - @DELETE - public Response remove() { - LogAction.logout(getUserId(), ServletHelper.retrieveRemoteAddress(request)); - request.getSession().removeAttribute(USER_ID_KEY); - return Response.noContent().build(); - } - - @Path("token") - @POST - public String requestToken( - @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { - return tokenManager.generateToken(getUserId(), expiration); - } - - @PermitAll - @Path("openid/auth") - @GET - public Response openIdAuth() throws IOException { - return Response.seeOther(openIdProvider.createAuthUri()).build(); - } - - @PermitAll - @Path("openid/callback") - @GET - public Response requestToken() throws IOException, StorageException, ParseException, GeneralSecurityException { - StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString()); - String queryString = request.getQueryString(); - String requestUri = requestUrl.append('?').append(queryString).toString(); - - return Response.seeOther(openIdProvider.handleCallback(URI.create(requestUri), request)).build(); - } -} +/* + * Copyright 2015 - 2022 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.api.resource; + +import org.traccar.api.BaseResource; +import org.traccar.api.security.LoginService; +import org.traccar.api.signature.TokenManager; +import org.traccar.database.OpenIdProvider; +import org.traccar.helper.DataConverter; +import org.traccar.helper.LogAction; +import org.traccar.helper.ServletHelper; +import org.traccar.model.User; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import com.nimbusds.oauth2.sdk.ParseException; +import javax.annotation.Nullable; +import javax.annotation.security.PermitAll; +import javax.inject.Inject; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.net.URI; + +@Path("session") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_FORM_URLENCODED) +public class SessionResource extends BaseResource { + + public static final String USER_ID_KEY = "userId"; + public static final String USER_COOKIE_KEY = "user"; + public static final String PASS_COOKIE_KEY = "password"; + + @Inject + private LoginService loginService; + + @Inject + @Nullable + private OpenIdProvider openIdProvider; + + @Inject + private TokenManager tokenManager; + + @Context + private HttpServletRequest request; + + @PermitAll + @GET + public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException { + + if (token != null) { + User user = loginService.login(token); + if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } + } + + Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); + if (userId == null) { + + Cookie[] cookies = request.getCookies(); + String email = null, password = null; + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals(USER_COOKIE_KEY)) { + byte[] emailBytes = DataConverter.parseBase64( + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); + email = new String(emailBytes, StandardCharsets.UTF_8); + } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { + byte[] passwordBytes = DataConverter.parseBase64( + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); + password = new String(passwordBytes, StandardCharsets.UTF_8); + } + } + } + if (email != null && password != null) { + User user = loginService.login(email, password); + if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } + } + + } else { + + User user = permissionsService.getUser(userId); + if (user != null) { + return user; + } + + } + + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); + } + + @Path("{id}") + @GET + public User get(@PathParam("id") long userId) throws StorageException { + permissionsService.checkUser(getUserId(), userId); + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", userId))); + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } + + @PermitAll + @POST + public User add( + @FormParam("email") String email, @FormParam("password") String password) throws StorageException { + User user = loginService.login(email, password); + if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } else { + LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request)); + throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); + } + } + + @DELETE + public Response remove() { + LogAction.logout(getUserId(), ServletHelper.retrieveRemoteAddress(request)); + request.getSession().removeAttribute(USER_ID_KEY); + return Response.noContent().build(); + } + + @Path("token") + @POST + public String requestToken( + @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { + return tokenManager.generateToken(getUserId(), expiration); + } + + @PermitAll + @Path("openid/auth") + @GET + public Response openIdAuth() throws IOException { + return Response.seeOther(openIdProvider.createAuthUri()).build(); + } + + @PermitAll + @Path("openid/callback") + @GET + public Response requestToken() throws IOException, StorageException, ParseException, GeneralSecurityException { + StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString()); + String queryString = request.getQueryString(); + String requestUri = requestUrl.append('?').append(queryString).toString(); + + return Response.seeOther(openIdProvider.handleCallback(URI.create(requestUri), request)).build(); + } +} diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 6f44d0e80..22e5d6b50 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -1,170 +1,163 @@ -/* - * Copyright 2023 Daniel Raper (me@danr.uk) - * - * 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.database; - -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.api.resource.SessionResource; -import org.traccar.api.security.LoginService; -import org.traccar.model.User; -import org.traccar.storage.StorageException; -import org.traccar.helper.LogAction; -import org.traccar.helper.ServletHelper; - -import java.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; -import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import com.google.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.nimbusds.oauth2.sdk.http.HTTPResponse; -import com.nimbusds.oauth2.sdk.AuthorizationCode; -import com.nimbusds.oauth2.sdk.ResponseType; -import com.nimbusds.oauth2.sdk.Scope; -import com.nimbusds.oauth2.sdk.AuthorizationGrant; -import com.nimbusds.oauth2.sdk.TokenRequest; -import com.nimbusds.oauth2.sdk.TokenResponse; -import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; -import com.nimbusds.oauth2.sdk.ParseException; -import com.nimbusds.oauth2.sdk.AuthorizationResponse; -import com.nimbusds.oauth2.sdk.auth.Secret; -import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; -import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; -import com.nimbusds.oauth2.sdk.token.BearerAccessToken; -import com.nimbusds.oauth2.sdk.id.State; -import com.nimbusds.oauth2.sdk.id.ClientID; -import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; -import com.nimbusds.openid.connect.sdk.Nonce; -import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; -import com.nimbusds.openid.connect.sdk.UserInfoResponse; -import com.nimbusds.openid.connect.sdk.UserInfoRequest; -import com.nimbusds.openid.connect.sdk.AuthenticationRequest; - -import com.nimbusds.openid.connect.sdk.claims.UserInfo; - -public class OpenIdProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdProvider.class); - - public final Boolean force; - private final ClientID clientId; - private final ClientAuthentication clientAuth; - private URI callbackUrl; - private URI authUrl; - private URI tokenUrl; - private URI userInfoUrl; - private URI baseUrl; - private final String adminGroup; - - private LoginService loginService; - - @Inject - public OpenIdProvider(Config config, LoginService loginService) { - this.loginService = loginService; - - force = config.getBoolean(Keys.OPENID_FORCE); - clientId = new ClientID(config.getString(Keys.OPENID_CLIENTID)); - clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENTSECRET))); - - try { - callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); - authUrl = new URI(config.getString(Keys.OPENID_AUTHURL, "")); - tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); - userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); - baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - } catch(URISyntaxException error) { - LOGGER.error("Invalid URIs provided in OpenID configuration"); - } - - adminGroup = config.getString(Keys.OPENID_ADMINGROUP); - } - - public URI createAuthUri() { - AuthenticationRequest request = new AuthenticationRequest.Builder( - new ResponseType("code"), - new Scope("openid", "profile", "email", "groups"), - clientId, - callbackUrl) - .endpointURI(authUrl) - .state(new State()) - .nonce(new Nonce()) - .build(); - - return request.toURI(); - } - - private OIDCTokenResponse getToken(AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { - AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); - TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); - - HTTPResponse tokenReq = tokenRequest.toHTTPRequest().send(); - TokenResponse tokenResponse = OIDCTokenResponseParser.parse(tokenReq); - if (!tokenResponse.indicatesSuccess()) { - LOGGER.warn("Invalid authorization code provided to OpenID callback"); - throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); - } - - return (OIDCTokenResponse) tokenResponse.toSuccessResponse(); - } - - private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException { - UserInfoResponse userInfoResponse; - - HTTPResponse httpResponse = new UserInfoRequest(userInfoUrl, token) - .toHTTPRequest() - .send(); - - userInfoResponse = UserInfoResponse.parse(httpResponse); - - if (!userInfoResponse.indicatesSuccess()) { - LOGGER.error("Failed to access OpenID user info endpoint"); - throw new GeneralSecurityException("Failed to access OpenID Connect user info endpoint. Please contact your administrator."); - } - - return userInfoResponse.toSuccessResponse().getUserInfo(); - } - - public URI handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, GeneralSecurityException { - AuthorizationResponse response = AuthorizationResponse.parse(requestUri); - - if (!response.indicatesSuccess()) { - LOGGER.warn("Callback received error response from OpenID identity provider"); - throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); - } - - AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); - - if (authCode == null) { - LOGGER.warn("Malformed OpenID callback"); - throw new GeneralSecurityException( "Malformed OpenID callback."); - } - - OIDCTokenResponse tokens = getToken(authCode); - - BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); - - UserInfo userInfo = getUserInfo(bearerToken); - - User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), userInfo.getStringListClaim("groups").contains(adminGroup)); - - request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - - return baseUrl; - } -} +/* + * Copyright 2023 Daniel Raper (me@danr.uk) + * + * 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.database; + +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.api.resource.SessionResource; +import org.traccar.api.security.LoginService; +import org.traccar.model.User; +import org.traccar.storage.StorageException; +import org.traccar.helper.LogAction; +import org.traccar.helper.ServletHelper; + +import java.net.URI; +import java.net.URISyntaxException; +import java.security.GeneralSecurityException; +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import com.google.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.nimbusds.oauth2.sdk.http.HTTPResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCode; +import com.nimbusds.oauth2.sdk.ResponseType; +import com.nimbusds.oauth2.sdk.Scope; +import com.nimbusds.oauth2.sdk.AuthorizationGrant; +import com.nimbusds.oauth2.sdk.TokenRequest; +import com.nimbusds.oauth2.sdk.TokenResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; +import com.nimbusds.oauth2.sdk.ParseException; +import com.nimbusds.oauth2.sdk.AuthorizationResponse; +import com.nimbusds.oauth2.sdk.auth.Secret; +import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; +import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; +import com.nimbusds.oauth2.sdk.token.BearerAccessToken; +import com.nimbusds.oauth2.sdk.id.State; +import com.nimbusds.oauth2.sdk.id.ClientID; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; +import com.nimbusds.openid.connect.sdk.Nonce; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; +import com.nimbusds.openid.connect.sdk.UserInfoResponse; +import com.nimbusds.openid.connect.sdk.UserInfoRequest; +import com.nimbusds.openid.connect.sdk.AuthenticationRequest; + +import com.nimbusds.openid.connect.sdk.claims.UserInfo; + +public class OpenIdProvider { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdProvider.class); + + public final Boolean force; + private final ClientID clientId; + private final ClientAuthentication clientAuth; + private URI callbackUrl; + private URI authUrl; + private URI tokenUrl; + private URI userInfoUrl; + private URI baseUrl; + private final String adminGroup; + + private LoginService loginService; + + @Inject + public OpenIdProvider(Config config, LoginService loginService) { + this.loginService = loginService; + + force = config.getBoolean(Keys.OPENID_FORCE); + clientId = new ClientID(config.getString(Keys.OPENID_CLIENTID)); + clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENTSECRET))); + + try { + callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); + authUrl = new URI(config.getString(Keys.OPENID_AUTHURL, "")); + tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); + userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); + baseUrl = new URI(config.getString(Keys.WEB_URL, "")); + } catch(URISyntaxException error) { + LOGGER.error("Invalid URIs provided in OpenID configuration"); + } + + adminGroup = config.getString(Keys.OPENID_ADMINGROUP); + } + + public URI createAuthUri() { + AuthenticationRequest.Builder request = new AuthenticationRequest.Builder( + new ResponseType("code"), + new Scope("openid", "profile", "email", "groups"), + clientId, + callbackUrl); + + return request.endpointURI(authUrl) + .state(new State()) + .build() + .toURI(); + } + + private OIDCTokenResponse getToken(AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { + AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); + TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); + + HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send(); + TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse); + if (!token.indicatesSuccess()) { + throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); + } + + return (OIDCTokenResponse) token.toSuccessResponse(); + } + + private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException { + HTTPResponse httpResponse = new UserInfoRequest(userInfoUrl, token) + .toHTTPRequest() + .send(); + + UserInfoResponse userInfoResponse = UserInfoResponse.parse(httpResponse); + + if (!userInfoResponse.indicatesSuccess()) { + throw new GeneralSecurityException("Failed to access OpenID Connect user info endpoint. Please contact your administrator."); + } + + return userInfoResponse.toSuccessResponse().getUserInfo(); + } + + public URI handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, GeneralSecurityException { + AuthorizationResponse response = AuthorizationResponse.parse(requestUri); + + if (!response.indicatesSuccess()) { + throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); + } + + AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); + + if (authCode == null) { + throw new GeneralSecurityException( "Malformed OpenID callback."); + } + + OIDCTokenResponse tokens = getToken(authCode); + + BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); + + UserInfo userInfo = getUserInfo(bearerToken); + + User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), userInfo.getStringListClaim("groups").contains(adminGroup)); + + request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + + return baseUrl; + } +} diff --git a/swagger.json b/swagger.json index d3a83ba76..5a7349da8 100644 --- a/swagger.json +++ b/swagger.json @@ -1,3542 +1,3526 @@ -{ - "openapi": "3.0.1", - "info": { - "title": "Traccar", - "version": "5.6", - "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", - "contact": { - "name": "Traccar Support", - "url": "https://www.traccar.org/", - "email": "support@traccar.org" - }, - "license": { - "name": "Apache 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0.html" - } - }, - "servers": [ - { - "url": "https://demo.traccar.org/api", - "description": "Demo Server 1" - }, - { - "url": "https://demo2.traccar.org/api", - "description": "Demo Server 2" - }, - { - "url": "https://demo3.traccar.org/api", - "description": "Demo Server 3" - }, - { - "url": "https://demo4.traccar.org/api", - "description": "Demo Server 4" - }, - { - "url": "https://server.traccar.org/api", - "description": "Subscription Server" - }, - { - "url": "http://{host}:{port}/api", - "description": "Other Server", - "variables": { - "host": { - "default": "localhost" - }, - "port": { - "enum": [ - "8082", - "80" - ], - "default": "8082" - } - } - } - ], - "security": [ - { - "basicAuth": [] - } - ], - "tags": [ - { - "name": "Server", - "description": "Server information" - }, - { - "name": "Session", - "description": "User session management" - }, - { - "name": "Devices", - "description": "Device management" - }, - { - "name": "Groups", - "description": "Group management" - }, - { - "name": "Users", - "description": "User management" - }, - { - "name": "Permissions", - "description": "User permissions and other object linking" - }, - { - "name": "Positions", - "description": "Retrieving raw location information" - }, - { - "name": "Events", - "description": "Retrieving event information" - }, - { - "name": "Reports", - "description": "Reports generation" - }, - { - "name": "Notifications", - "description": "User notifications management" - }, - { - "name": "Geofences", - "description": "Geofence management" - }, - { - "name": "Commands", - "description": "Sending commands to devices and stored command management" - }, - { - "name": "Attributes", - "description": "Computed attributes management" - }, - { - "name": "Drivers", - "description": "Drivers management" - }, - { - "name": "Maintenance", - "description": "Maintenance management" - }, - { - "name": "Calendars", - "description": "Calendar management" - }, - { - "name": "Statistics", - "description": "Retrieving server statistics" - } - ], - "paths": { - "/commands": { - "get": { - "summary": "Fetch a list of Saved Commands", - "tags": [ - "Commands" - ], - "description": "Without params, it returns a list of Saved Commands the user has access to", - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Command" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Saved Command", - "tags": [ - "Commands" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/commands/{id}": { - "put": { - "summary": "Update a Saved Command", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Saved Command", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/commands/send": { - "get": { - "summary": "Fetch a list of Saved Commands supported by Device at the moment", - "description": "Return a list of saved commands linked to Device and its groups, filtered by current Device protocol support", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Command" - } - } - } - } - }, - "400": { - "description": "Could happen when the user doesn't have permission for the device", - "content": {} - } - } - }, - "post": { - "summary": "Dispatch commands to device", - "description": "Dispatch a new command or Saved Command if _body.id_ set", - "tags": [ - "Commands" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Command sent", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - }, - "202": { - "description": "Command queued", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - }, - "400": { - "description": "Could happen when the user doesn't have permission or an incorrect command _type_ for the device", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/commands/types": { - "get": { - "summary": "Fetch a list of available Commands for the Device or all possible Commands if Device ommited", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "description": "Internal device identifier. Only works if device has already reported some locations", - "schema": { - "type": "integer" - } - }, - { - "name": "protocol", - "in": "query", - "description": "Protocol name. Can be used instead of device id", - "schema": { - "type": "string" - } - }, - { - "name": "textChannel", - "in": "query", - "description": "When `true` return SMS commands. If not specified or `false` return data commands", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CommandType" - } - } - } - } - }, - "400": { - "description": "Could happen when trying to fetch from a device the user does not have permission", - "content": {} - } - } - } - }, - "/devices": { - "get": { - "summary": "Fetch a list of Devices", - "description": "Without any params, returns a list of the user's devices", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "id", - "in": "query", - "description": "To fetch one or more devices. Multiple params can be passed like `id=31&id=42`", - "schema": { - "type": "integer" - } - }, - { - "name": "uniqueId", - "in": "query", - "description": "To fetch one or more devices. Multiple params can be passed like `uniqueId=333331&uniqieId=44442`", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Device" - } - } - } - } - }, - "400": { - "description": "No permission", - "content": {} - } - } - }, - "post": { - "summary": "Create a Device", - "tags": [ - "Devices" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/devices/{id}": { - "put": { - "summary": "Update a Device", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Device", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/devices/{id}/accumulators": { - "put": { - "summary": "Update total distance and hours of the Device", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeviceAccumulators" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "No Content", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/groups": { - "get": { - "summary": "Fetch a list of Groups", - "description": "Without any params, returns a list of the Groups the user belongs to", - "tags": [ - "Groups" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Group" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Group", - "tags": [ - "Groups" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - } - }, - "400": { - "description": "No permission", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/groups/{id}": { - "put": { - "summary": "Update a Group", - "tags": [ - "Groups" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Group", - "tags": [ - "Groups" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/permissions": { - "post": { - "summary": "Link an Object to another Object", - "tags": [ - "Permissions" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "No Content", - "content": {} - }, - "400": { - "description": "No permission", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Unlink an Object from another Object", - "tags": [ - "Permissions" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "No Content", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/positions": { - "get": { - "summary": "Fetches a list of Positions", - "description": "We strongly recommend using [Traccar WebSocket API](https://www.traccar.org/traccar-api/) instead of periodically polling positions endpoint. Without any params, it returns a list of last known positions for all the user's Devices. _from_ and _to_ fields are not required with _id_.", - "tags": [ - "Positions" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "description": "_deviceId_ is optional, but requires the _from_ and _to_ parameters when used", - "schema": { - "type": "integer" - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "id", - "in": "query", - "description": "To fetch one or more positions. Multiple params can be passed like `id=31&id=42`", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - }, - "text/csv": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - }, - "application/gpx+xml": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - } - } - } - } - } - }, - "/server": { - "get": { - "summary": "Fetch Server information", - "tags": [ - "Server" - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Server" - } - } - } - } - } - }, - "put": { - "summary": "Update Server information", - "tags": [ - "Server" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Server" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Server" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/session": { - "get": { - "summary": "Fetch Session information", - "tags": [ - "Session" - ], - "parameters": [ - { - "name": "token", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - }, - "404": { - "description": "Not Found", - "content": {} - } - } - }, - "post": { - "summary": "Create a new Session", - "tags": [ - "Session" - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "required": [ - "email", - "password" - ], - "properties": { - "email": { - "type": "string" - }, - "password": { - "type": "string", - "format": "password" - } - } - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": {} - } - } - }, - "delete": { - "summary": "Close the Session", - "tags": [ - "Session" - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/session/openid/auth": { - "get": { - "summary": "Fetch Session information", - "tags": [ - "Session" - ], - "parameters": [ - { - } - ], - "responses": { - "303": { - "description": "Redirect to OpenID Connect identity provider", - "content": { } - }, - "404": { - "description": "OpenID Connect disabled", - "content": { } - } - } - } - }, - "/session/openid/callback": { - "get": { - "summary": "OpenID Callback", - "tags": [ - "Session" - ], - "parameters": [ - { - } - ], - "responses": { - "303": { - "description": "Successful authentication, redirect to homepage", - "content": { } - }, - "403": { - "description": "Invalid callback or negative response from identity provider", - "content": { } - }, - "404": { - "description": "OpenID Connect disabled", - "content": { } - }, - "500": { - "description": "Other OpenID Connect error", - "content": { } - } - } - } - }, - "/users": { - "get": { - "summary": "Fetch a list of Users", - "tags": [ - "Users" - ], - "parameters": [ - { - "name": "userId", - "in": "query", - "description": "Can only be used by admin or manager users", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/User" - } - } - } - } - }, - "400": { - "description": "No Permission", - "content": {} - } - } - }, - "post": { - "summary": "Create a User", - "tags": [ - "Users" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/users/{id}": { - "put": { - "summary": "Update a User", - "tags": [ - "Users" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a User", - "tags": [ - "Users" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/notifications": { - "get": { - "summary": "Fetch a list of Notifications", - "description": "Without params, it returns a list of Notifications the user has access to", - "tags": [ - "Notifications" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Notification" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Notification", - "tags": [ - "Notifications" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/notifications/{id}": { - "put": { - "summary": "Update a Notification", - "tags": [ - "Notifications" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Notification", - "tags": [ - "Notifications" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/notifications/types": { - "get": { - "summary": "Fetch a list of available Notification types", - "tags": [ - "Notifications" - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationType" - } - } - } - } - } - } - } - }, - "/notifications/test": { - "post": { - "summary": "Send test notification to current user via Email and SMS", - "tags": [ - "Notifications" - ], - "responses": { - "204": { - "description": "Successful sending", - "content": {} - }, - "400": { - "description": "Could happen if sending has failed", - "content": {} - } - } - } - }, - "/geofences": { - "get": { - "summary": "Fetch a list of Geofences", - "description": "Without params, it returns a list of Geofences the user has access to", - "tags": [ - "Geofences" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Geofence" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Geofence", - "tags": [ - "Geofences" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/geofences/{id}": { - "put": { - "summary": "Update a Geofence", - "tags": [ - "Geofences" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Geofence", - "tags": [ - "Geofences" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/events/{id}": { - "get": { - "tags": [ - "Events" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Event" - } - } - } - } - } - } - }, - "/reports/route": { - "get": { - "summary": "Fetch a list of Positions within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - } - } - } - } - } - }, - "/reports/events": { - "get": { - "summary": "Fetch a list of Events within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "type", - "in": "query", - "description": "% can be used to return events of all types", - "style": "form", - "explode": false, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Event" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Event" - } - } - } - } - } - } - } - }, - "/reports/summary": { - "get": { - "summary": "Fetch a list of ReportSummary within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportSummary" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportSummary" - } - } - } - } - } - } - } - }, - "/reports/trips": { - "get": { - "summary": "Fetch a list of ReportTrips within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportTrips" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportTrips" - } - } - } - } - } - } - } - }, - "/reports/stops": { - "get": { - "summary": "Fetch a list of ReportStops within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportStops" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportStops" - } - } - } - } - } - } - } - }, - "/statistics": { - "get": { - "summary": "Fetch server Statistics", - "tags": [ - "Statistics" - ], - "parameters": [ - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Statistics" - } - } - } - } - } - } - } - }, - "/calendars": { - "get": { - "summary": "Fetch a list of Calendars", - "description": "Without params, it returns a list of Calendars the user has access to", - "tags": [ - "Calendars" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Calendar" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Calendar", - "tags": [ - "Calendars" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/calendars/{id}": { - "put": { - "summary": "Update a Calendar", - "tags": [ - "Calendars" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Calendar", - "tags": [ - "Calendars" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/attributes/computed": { - "get": { - "summary": "Fetch a list of Attributes", - "description": "Without params, it returns a list of Attributes the user has access to", - "tags": [ - "Attributes" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Attribute" - } - } - } - } - } - } - }, - "post": { - "summary": "Create an Attribute", - "tags": [ - "Attributes" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/attributes/computed/{id}": { - "put": { - "summary": "Update an Attribute", - "tags": [ - "Attributes" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete an Attribute", - "tags": [ - "Attributes" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/drivers": { - "get": { - "summary": "Fetch a list of Drivers", - "description": "Without params, it returns a list of Drivers the user has access to", - "tags": [ - "Drivers" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Driver" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Driver", - "tags": [ - "Drivers" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/drivers/{id}": { - "put": { - "summary": "Update a Driver", - "tags": [ - "Drivers" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Driver", - "tags": [ - "Drivers" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/maintenance": { - "get": { - "summary": "Fetch a list of Maintenance", - "description": "Without params, it returns a list of Maintenance the user has access to", - "tags": [ - "Maintenance" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Maintenance" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Maintenance", - "tags": [ - "Maintenance" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/maintenance/{id}": { - "put": { - "summary": "Update a Maintenance", - "tags": [ - "Maintenance" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Maintenance", - "tags": [ - "Maintenance" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - } - }, - "components": { - "schemas": { - "Position": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "deviceId": { - "type": "integer" - }, - "protocol": { - "type": "string" - }, - "deviceTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "fixTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "serverTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "outdated": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - }, - "latitude": { - "type": "number" - }, - "longitude": { - "type": "number" - }, - "altitude": { - "type": "number" - }, - "speed": { - "type": "number", - "description": "in knots" - }, - "course": { - "type": "number" - }, - "address": { - "type": "string" - }, - "accuracy": { - "type": "number" - }, - "network": { - "type": "object", - "properties": {} - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "User": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "email": { - "type": "string" - }, - "phone": { - "type": "string" - }, - "readonly": { - "type": "boolean" - }, - "administrator": { - "type": "boolean" - }, - "map": { - "type": "string" - }, - "latitude": { - "type": "number" - }, - "longitude": { - "type": "number" - }, - "zoom": { - "type": "integer" - }, - "password": { - "type": "string" - }, - "twelveHourFormat": { - "type": "boolean" - }, - "coordinateFormat": { - "type": "string" - }, - "disabled": { - "type": "boolean" - }, - "expirationTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "deviceLimit": { - "type": "integer" - }, - "userLimit": { - "type": "integer" - }, - "deviceReadonly": { - "type": "boolean" - }, - "limitCommands": { - "type": "boolean" - }, - "poiLayer": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Server": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "registration": { - "type": "boolean" - }, - "readonly": { - "type": "boolean" - }, - "deviceReadonly": { - "type": "boolean" - }, - "limitCommands": { - "type": "boolean" - }, - "map": { - "type": "string" - }, - "bingKey": { - "type": "string" - }, - "mapUrl": { - "type": "string" - }, - "poiLayer": { - "type": "string" - }, - "latitude": { - "type": "number" - }, - "longitude": { - "type": "number" - }, - "zoom": { - "type": "integer" - }, - "twelveHourFormat": { - "type": "boolean" - }, - "version": { - "type": "string" - }, - "forceSettings": { - "type": "boolean" - }, - "coordinateFormat": { - "type": "string" - }, - "oidcEnabled": { - "type": "boolean" - }, - "oidcForce": { - "type": "boolean" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Command": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "deviceId": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "type": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Device": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "uniqueId": { - "type": "string" - }, - "status": { - "type": "string" - }, - "disabled": { - "type": "boolean" - }, - "lastUpdate": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "positionId": { - "type": "integer" - }, - "groupId": { - "type": "integer" - }, - "phone": { - "type": "string" - }, - "model": { - "type": "string" - }, - "contact": { - "type": "string" - }, - "category": { - "type": "string" - }, - "geofenceIds": { - "type": "array", - "items": { - "type": "integer" - } - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Group": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "groupId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Permission": { - "type": "object", - "properties": { - "userId": { - "type": "integer", - "description": "User Id, can be only first parameter" - }, - "deviceId": { - "type": "integer", - "description": "Device Id, can be first parameter or second only in combination with userId" - }, - "groupId": { - "type": "integer", - "description": "Group Id, can be first parameter or second only in combination with userId" - }, - "geofenceId": { - "type": "integer", - "description": "Geofence Id, can be second parameter only" - }, - "notificationId": { - "type": "integer", - "description": "Notification Id, can be second parameter only" - }, - "calendarId": { - "type": "integer", - "description": "Calendar Id, can be second parameter only and only in combination with userId" - }, - "attributeId": { - "type": "integer", - "description": "Computed Attribute Id, can be second parameter only" - }, - "driverId": { - "type": "integer", - "description": "Driver Id, can be second parameter only" - }, - "managedUserId": { - "type": "integer", - "description": "User Id, can be second parameter only and only in combination with userId" - } - }, - "description": "This is a permission map that contain two object indexes. It is used to link/unlink objects. Order is important. Example: { deviceId:8, geofenceId: 16 }" - }, - "CommandType": { - "type": "object", - "properties": { - "type": { - "type": "string" - } - } - }, - "Geofence": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "area": { - "type": "string" - }, - "calendarId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Notification": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "always": { - "type": "boolean" - }, - "web": { - "type": "boolean" - }, - "mail": { - "type": "boolean" - }, - "sms": { - "type": "boolean" - }, - "calendarId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "NotificationType": { - "type": "object", - "properties": { - "type": { - "type": "string" - } - } - }, - "Event": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "eventTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "deviceId": { - "type": "integer" - }, - "positionId": { - "type": "integer" - }, - "geofenceId": { - "type": "integer" - }, - "maintenanceId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "ReportSummary": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "deviceName": { - "type": "string" - }, - "maxSpeed": { - "type": "number", - "description": "in knots" - }, - "averageSpeed": { - "type": "number", - "description": "in knots" - }, - "distance": { - "type": "number", - "description": "in meters" - }, - "spentFuel": { - "type": "number", - "description": "in liters" - }, - "engineHours": { - "type": "integer" - } - } - }, - "ReportTrips": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "deviceName": { - "type": "string" - }, - "maxSpeed": { - "type": "number", - "description": "in knots" - }, - "averageSpeed": { - "type": "number", - "description": "in knots" - }, - "distance": { - "type": "number", - "description": "in meters" - }, - "spentFuel": { - "type": "number", - "description": "in liters" - }, - "duration": { - "type": "integer" - }, - "startTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "startAddress": { - "type": "string" - }, - "startLat": { - "type": "number" - }, - "startLon": { - "type": "number" - }, - "endTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "endAddress": { - "type": "string" - }, - "endLat": { - "type": "number" - }, - "endLon": { - "type": "number" - }, - "driverUniqueId": { - "type": "integer" - }, - "driverName": { - "type": "string" - } - } - }, - "ReportStops": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "deviceName": { - "type": "string" - }, - "duration": { - "type": "integer" - }, - "startTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "address": { - "type": "string" - }, - "lat": { - "type": "number" - }, - "lon": { - "type": "number" - }, - "endTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "spentFuel": { - "type": "number", - "description": "in liters" - }, - "engineHours": { - "type": "integer" - } - } - }, - "Statistics": { - "type": "object", - "properties": { - "captureTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "activeUsers": { - "type": "integer" - }, - "activeDevices": { - "type": "integer" - }, - "requests": { - "type": "integer" - }, - "messagesReceived": { - "type": "integer" - }, - "messagesStored": { - "type": "integer" - } - } - }, - "DeviceAccumulators": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "totalDistance": { - "type": "number", - "description": "in meters" - }, - "hours": { - "type": "number" - } - } - }, - "Calendar": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "data": { - "type": "string", - "description": "base64 encoded in iCalendar format" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Attribute": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "attribute": { - "type": "string" - }, - "expression": { - "type": "string" - }, - "type": { - "type": "string", - "description": "String|Number|Boolean" - } - } - }, - "Driver": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "uniqueId": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Maintenance": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "type": { - "type": "string" - }, - "start": { - "type": "number" - }, - "period": { - "type": "number" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - } - }, - "parameters": { - "entityId": { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - }, - "all": { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - "refresh": { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - }, - "userId": { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - "deviceId": { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - "groupId": { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - "deviceIdArray": { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - "groupIdArray": { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - "fromTime": { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - "toTime": { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - }, - "requestBodies": { - "Device": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - }, - "required": true - }, - "Permission": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - }, - "required": true - }, - "Group": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - }, - "required": true - }, - "User": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - }, - "required": true - }, - "Geofence": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - }, - "required": true - }, - "Calendar": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - }, - "required": true - }, - "Attribute": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - }, - "required": true - }, - "Driver": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - }, - "required": true - }, - "Command": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "Notification": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - }, - "required": true - }, - "Maintenance": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - }, - "required": true - } - }, - "securitySchemes": { - "basicAuth": { - "type": "http", - "description": "Basic HTTP authorization with _email_ and _password_", - "scheme": "basic" - } - } - } -} +{ + "openapi": "3.0.1", + "info": { + "title": "Traccar", + "version": "5.6", + "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", + "contact": { + "name": "Traccar Support", + "url": "https://www.traccar.org/", + "email": "support@traccar.org" + }, + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "https://demo.traccar.org/api", + "description": "Demo Server 1" + }, + { + "url": "https://demo2.traccar.org/api", + "description": "Demo Server 2" + }, + { + "url": "https://demo3.traccar.org/api", + "description": "Demo Server 3" + }, + { + "url": "https://demo4.traccar.org/api", + "description": "Demo Server 4" + }, + { + "url": "https://server.traccar.org/api", + "description": "Subscription Server" + }, + { + "url": "http://{host}:{port}/api", + "description": "Other Server", + "variables": { + "host": { + "default": "localhost" + }, + "port": { + "enum": [ + "8082", + "80" + ], + "default": "8082" + } + } + } + ], + "security": [ + { + "basicAuth": [] + } + ], + "tags": [ + { + "name": "Server", + "description": "Server information" + }, + { + "name": "Session", + "description": "User session management" + }, + { + "name": "Devices", + "description": "Device management" + }, + { + "name": "Groups", + "description": "Group management" + }, + { + "name": "Users", + "description": "User management" + }, + { + "name": "Permissions", + "description": "User permissions and other object linking" + }, + { + "name": "Positions", + "description": "Retrieving raw location information" + }, + { + "name": "Events", + "description": "Retrieving event information" + }, + { + "name": "Reports", + "description": "Reports generation" + }, + { + "name": "Notifications", + "description": "User notifications management" + }, + { + "name": "Geofences", + "description": "Geofence management" + }, + { + "name": "Commands", + "description": "Sending commands to devices and stored command management" + }, + { + "name": "Attributes", + "description": "Computed attributes management" + }, + { + "name": "Drivers", + "description": "Drivers management" + }, + { + "name": "Maintenance", + "description": "Maintenance management" + }, + { + "name": "Calendars", + "description": "Calendar management" + }, + { + "name": "Statistics", + "description": "Retrieving server statistics" + } + ], + "paths": { + "/commands": { + "get": { + "summary": "Fetch a list of Saved Commands", + "tags": [ + "Commands" + ], + "description": "Without params, it returns a list of Saved Commands the user has access to", + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Command" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Saved Command", + "tags": [ + "Commands" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/commands/{id}": { + "put": { + "summary": "Update a Saved Command", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Saved Command", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/commands/send": { + "get": { + "summary": "Fetch a list of Saved Commands supported by Device at the moment", + "description": "Return a list of saved commands linked to Device and its groups, filtered by current Device protocol support", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Command" + } + } + } + } + }, + "400": { + "description": "Could happen when the user doesn't have permission for the device", + "content": {} + } + } + }, + "post": { + "summary": "Dispatch commands to device", + "description": "Dispatch a new command or Saved Command if _body.id_ set", + "tags": [ + "Commands" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Command sent", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + }, + "202": { + "description": "Command queued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + }, + "400": { + "description": "Could happen when the user doesn't have permission or an incorrect command _type_ for the device", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/commands/types": { + "get": { + "summary": "Fetch a list of available Commands for the Device or all possible Commands if Device ommited", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "Internal device identifier. Only works if device has already reported some locations", + "schema": { + "type": "integer" + } + }, + { + "name": "protocol", + "in": "query", + "description": "Protocol name. Can be used instead of device id", + "schema": { + "type": "string" + } + }, + { + "name": "textChannel", + "in": "query", + "description": "When `true` return SMS commands. If not specified or `false` return data commands", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandType" + } + } + } + } + }, + "400": { + "description": "Could happen when trying to fetch from a device the user does not have permission", + "content": {} + } + } + } + }, + "/devices": { + "get": { + "summary": "Fetch a list of Devices", + "description": "Without any params, returns a list of the user's devices", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "id", + "in": "query", + "description": "To fetch one or more devices. Multiple params can be passed like `id=31&id=42`", + "schema": { + "type": "integer" + } + }, + { + "name": "uniqueId", + "in": "query", + "description": "To fetch one or more devices. Multiple params can be passed like `uniqueId=333331&uniqieId=44442`", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Device" + } + } + } + } + }, + "400": { + "description": "No permission", + "content": {} + } + } + }, + "post": { + "summary": "Create a Device", + "tags": [ + "Devices" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/devices/{id}": { + "put": { + "summary": "Update a Device", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Device", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/devices/{id}/accumulators": { + "put": { + "summary": "Update total distance and hours of the Device", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceAccumulators" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No Content", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/groups": { + "get": { + "summary": "Fetch a list of Groups", + "description": "Without any params, returns a list of the Groups the user belongs to", + "tags": [ + "Groups" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Group" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Group", + "tags": [ + "Groups" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + } + }, + "400": { + "description": "No permission", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/groups/{id}": { + "put": { + "summary": "Update a Group", + "tags": [ + "Groups" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Group", + "tags": [ + "Groups" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/permissions": { + "post": { + "summary": "Link an Object to another Object", + "tags": [ + "Permissions" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Permission" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No Content", + "content": {} + }, + "400": { + "description": "No permission", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Unlink an Object from another Object", + "tags": [ + "Permissions" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Permission" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No Content", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/positions": { + "get": { + "summary": "Fetches a list of Positions", + "description": "We strongly recommend using [Traccar WebSocket API](https://www.traccar.org/traccar-api/) instead of periodically polling positions endpoint. Without any params, it returns a list of last known positions for all the user's Devices. _from_ and _to_ fields are not required with _id_.", + "tags": [ + "Positions" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "_deviceId_ is optional, but requires the _from_ and _to_ parameters when used", + "schema": { + "type": "integer" + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "id", + "in": "query", + "description": "To fetch one or more positions. Multiple params can be passed like `id=31&id=42`", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + }, + "application/gpx+xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + } + } + } + } + } + }, + "/server": { + "get": { + "summary": "Fetch Server information", + "tags": [ + "Server" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Server" + } + } + } + } + } + }, + "put": { + "summary": "Update Server information", + "tags": [ + "Server" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Server" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Server" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/session": { + "get": { + "summary": "Fetch Session information", + "tags": [ + "Session" + ], + "parameters": [ + { + "name": "token", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "404": { + "description": "Not Found", + "content": {} + } + } + }, + "post": { + "summary": "Create a new Session", + "tags": [ + "Session" + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string", + "format": "password" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": {} + } + } + }, + "delete": { + "summary": "Close the Session", + "tags": [ + "Session" + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/session/openid/auth": { + "get": { + "summary": "Fetch Session information", + "tags": [ + "Session" + ], + "parameters": [ + { + } + ], + "responses": { + "303": { + "description": "Redirect to OpenID Connect identity provider", + "content": { } + } + } + } + }, + "/session/openid/callback": { + "get": { + "summary": "OpenID Callback", + "tags": [ + "Session" + ], + "parameters": [ + { + } + ], + "responses": { + "303": { + "description": "Successful authentication, redirect to homepage", + "content": { } + } + } + } + }, + "/users": { + "get": { + "summary": "Fetch a list of Users", + "tags": [ + "Users" + ], + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Can only be used by admin or manager users", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "400": { + "description": "No Permission", + "content": {} + } + } + }, + "post": { + "summary": "Create a User", + "tags": [ + "Users" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/users/{id}": { + "put": { + "summary": "Update a User", + "tags": [ + "Users" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a User", + "tags": [ + "Users" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/notifications": { + "get": { + "summary": "Fetch a list of Notifications", + "description": "Without params, it returns a list of Notifications the user has access to", + "tags": [ + "Notifications" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Notification" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Notification", + "tags": [ + "Notifications" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/notifications/{id}": { + "put": { + "summary": "Update a Notification", + "tags": [ + "Notifications" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Notification", + "tags": [ + "Notifications" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/notifications/types": { + "get": { + "summary": "Fetch a list of available Notification types", + "tags": [ + "Notifications" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationType" + } + } + } + } + } + } + } + }, + "/notifications/test": { + "post": { + "summary": "Send test notification to current user via Email and SMS", + "tags": [ + "Notifications" + ], + "responses": { + "204": { + "description": "Successful sending", + "content": {} + }, + "400": { + "description": "Could happen if sending has failed", + "content": {} + } + } + } + }, + "/geofences": { + "get": { + "summary": "Fetch a list of Geofences", + "description": "Without params, it returns a list of Geofences the user has access to", + "tags": [ + "Geofences" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Geofence" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Geofence", + "tags": [ + "Geofences" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/geofences/{id}": { + "put": { + "summary": "Update a Geofence", + "tags": [ + "Geofences" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Geofence", + "tags": [ + "Geofences" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/events/{id}": { + "get": { + "tags": [ + "Events" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event" + } + } + } + } + } + } + }, + "/reports/route": { + "get": { + "summary": "Fetch a list of Positions within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + } + } + } + } + } + }, + "/reports/events": { + "get": { + "summary": "Fetch a list of Events within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "type", + "in": "query", + "description": "% can be used to return events of all types", + "style": "form", + "explode": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Event" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Event" + } + } + } + } + } + } + } + }, + "/reports/summary": { + "get": { + "summary": "Fetch a list of ReportSummary within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportSummary" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportSummary" + } + } + } + } + } + } + } + }, + "/reports/trips": { + "get": { + "summary": "Fetch a list of ReportTrips within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportTrips" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportTrips" + } + } + } + } + } + } + } + }, + "/reports/stops": { + "get": { + "summary": "Fetch a list of ReportStops within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportStops" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportStops" + } + } + } + } + } + } + } + }, + "/statistics": { + "get": { + "summary": "Fetch server Statistics", + "tags": [ + "Statistics" + ], + "parameters": [ + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Statistics" + } + } + } + } + } + } + } + }, + "/calendars": { + "get": { + "summary": "Fetch a list of Calendars", + "description": "Without params, it returns a list of Calendars the user has access to", + "tags": [ + "Calendars" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Calendar" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Calendar", + "tags": [ + "Calendars" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/calendars/{id}": { + "put": { + "summary": "Update a Calendar", + "tags": [ + "Calendars" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Calendar", + "tags": [ + "Calendars" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/attributes/computed": { + "get": { + "summary": "Fetch a list of Attributes", + "description": "Without params, it returns a list of Attributes the user has access to", + "tags": [ + "Attributes" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Attribute" + } + } + } + } + } + } + }, + "post": { + "summary": "Create an Attribute", + "tags": [ + "Attributes" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/attributes/computed/{id}": { + "put": { + "summary": "Update an Attribute", + "tags": [ + "Attributes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete an Attribute", + "tags": [ + "Attributes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/drivers": { + "get": { + "summary": "Fetch a list of Drivers", + "description": "Without params, it returns a list of Drivers the user has access to", + "tags": [ + "Drivers" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Driver" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Driver", + "tags": [ + "Drivers" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/drivers/{id}": { + "put": { + "summary": "Update a Driver", + "tags": [ + "Drivers" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Driver", + "tags": [ + "Drivers" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/maintenance": { + "get": { + "summary": "Fetch a list of Maintenance", + "description": "Without params, it returns a list of Maintenance the user has access to", + "tags": [ + "Maintenance" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Maintenance" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Maintenance", + "tags": [ + "Maintenance" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/maintenance/{id}": { + "put": { + "summary": "Update a Maintenance", + "tags": [ + "Maintenance" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Maintenance", + "tags": [ + "Maintenance" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + } + }, + "components": { + "schemas": { + "Position": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "deviceId": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "deviceTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "fixTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "serverTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "outdated": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "altitude": { + "type": "number" + }, + "speed": { + "type": "number", + "description": "in knots" + }, + "course": { + "type": "number" + }, + "address": { + "type": "string" + }, + "accuracy": { + "type": "number" + }, + "network": { + "type": "object", + "properties": {} + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "readonly": { + "type": "boolean" + }, + "administrator": { + "type": "boolean" + }, + "map": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "zoom": { + "type": "integer" + }, + "password": { + "type": "string" + }, + "twelveHourFormat": { + "type": "boolean" + }, + "coordinateFormat": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "expirationTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "deviceLimit": { + "type": "integer" + }, + "userLimit": { + "type": "integer" + }, + "deviceReadonly": { + "type": "boolean" + }, + "limitCommands": { + "type": "boolean" + }, + "poiLayer": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Server": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "registration": { + "type": "boolean" + }, + "readonly": { + "type": "boolean" + }, + "deviceReadonly": { + "type": "boolean" + }, + "limitCommands": { + "type": "boolean" + }, + "map": { + "type": "string" + }, + "bingKey": { + "type": "string" + }, + "mapUrl": { + "type": "string" + }, + "poiLayer": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "zoom": { + "type": "integer" + }, + "twelveHourFormat": { + "type": "boolean" + }, + "version": { + "type": "string" + }, + "forceSettings": { + "type": "boolean" + }, + "coordinateFormat": { + "type": "string" + }, + "openIdEnabled": { + "type": "boolean" + }, + "openIdForce": { + "type": "boolean" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Command": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "deviceId": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Device": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "uniqueId": { + "type": "string" + }, + "status": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "lastUpdate": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "positionId": { + "type": "integer" + }, + "groupId": { + "type": "integer" + }, + "phone": { + "type": "string" + }, + "model": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "category": { + "type": "string" + }, + "geofenceIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Group": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Permission": { + "type": "object", + "properties": { + "userId": { + "type": "integer", + "description": "User Id, can be only first parameter" + }, + "deviceId": { + "type": "integer", + "description": "Device Id, can be first parameter or second only in combination with userId" + }, + "groupId": { + "type": "integer", + "description": "Group Id, can be first parameter or second only in combination with userId" + }, + "geofenceId": { + "type": "integer", + "description": "Geofence Id, can be second parameter only" + }, + "notificationId": { + "type": "integer", + "description": "Notification Id, can be second parameter only" + }, + "calendarId": { + "type": "integer", + "description": "Calendar Id, can be second parameter only and only in combination with userId" + }, + "attributeId": { + "type": "integer", + "description": "Computed Attribute Id, can be second parameter only" + }, + "driverId": { + "type": "integer", + "description": "Driver Id, can be second parameter only" + }, + "managedUserId": { + "type": "integer", + "description": "User Id, can be second parameter only and only in combination with userId" + } + }, + "description": "This is a permission map that contain two object indexes. It is used to link/unlink objects. Order is important. Example: { deviceId:8, geofenceId: 16 }" + }, + "CommandType": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + }, + "Geofence": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "area": { + "type": "string" + }, + "calendarId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Notification": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "always": { + "type": "boolean" + }, + "web": { + "type": "boolean" + }, + "mail": { + "type": "boolean" + }, + "sms": { + "type": "boolean" + }, + "calendarId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "NotificationType": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + }, + "Event": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "eventTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "deviceId": { + "type": "integer" + }, + "positionId": { + "type": "integer" + }, + "geofenceId": { + "type": "integer" + }, + "maintenanceId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "ReportSummary": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "maxSpeed": { + "type": "number", + "description": "in knots" + }, + "averageSpeed": { + "type": "number", + "description": "in knots" + }, + "distance": { + "type": "number", + "description": "in meters" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "engineHours": { + "type": "integer" + } + } + }, + "ReportTrips": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "maxSpeed": { + "type": "number", + "description": "in knots" + }, + "averageSpeed": { + "type": "number", + "description": "in knots" + }, + "distance": { + "type": "number", + "description": "in meters" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "duration": { + "type": "integer" + }, + "startTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "startAddress": { + "type": "string" + }, + "startLat": { + "type": "number" + }, + "startLon": { + "type": "number" + }, + "endTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "endAddress": { + "type": "string" + }, + "endLat": { + "type": "number" + }, + "endLon": { + "type": "number" + }, + "driverUniqueId": { + "type": "integer" + }, + "driverName": { + "type": "string" + } + } + }, + "ReportStops": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "duration": { + "type": "integer" + }, + "startTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "address": { + "type": "string" + }, + "lat": { + "type": "number" + }, + "lon": { + "type": "number" + }, + "endTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "engineHours": { + "type": "integer" + } + } + }, + "Statistics": { + "type": "object", + "properties": { + "captureTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "activeUsers": { + "type": "integer" + }, + "activeDevices": { + "type": "integer" + }, + "requests": { + "type": "integer" + }, + "messagesReceived": { + "type": "integer" + }, + "messagesStored": { + "type": "integer" + } + } + }, + "DeviceAccumulators": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "totalDistance": { + "type": "number", + "description": "in meters" + }, + "hours": { + "type": "number" + } + } + }, + "Calendar": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "data": { + "type": "string", + "description": "base64 encoded in iCalendar format" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Attribute": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "attribute": { + "type": "string" + }, + "expression": { + "type": "string" + }, + "type": { + "type": "string", + "description": "String|Number|Boolean" + } + } + }, + "Driver": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "uniqueId": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Maintenance": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "start": { + "type": "number" + }, + "period": { + "type": "number" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + } + }, + "parameters": { + "entityId": { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + "all": { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + "refresh": { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + }, + "userId": { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + "deviceId": { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + "groupId": { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + "deviceIdArray": { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "groupIdArray": { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "fromTime": { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + "toTime": { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + }, + "requestBodies": { + "Device": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + }, + "required": true + }, + "Permission": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Permission" + } + } + }, + "required": true + }, + "Group": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + }, + "required": true + }, + "User": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "Geofence": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + }, + "required": true + }, + "Calendar": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + }, + "required": true + }, + "Attribute": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + }, + "required": true + }, + "Driver": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + }, + "required": true + }, + "Command": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "Notification": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + }, + "required": true + }, + "Maintenance": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + }, + "required": true + } + }, + "securitySchemes": { + "basicAuth": { + "type": "http", + "description": "Basic HTTP authorization with _email_ and _password_", + "scheme": "basic" + } + } + } +} -- cgit v1.2.3 From 256492e692ee881842782d5dc0932a4b742c75a8 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 17:31:34 +0100 Subject: Create user defaults method --- .../org/traccar/api/resource/UserResource.java | 235 ++++++++++---------- .../org/traccar/api/security/LoginService.java | 242 +++++++++++---------- .../java/org/traccar/helper/model/UserUtil.java | 146 +++++++------ traccar-web | 2 +- 4 files changed, 317 insertions(+), 308 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index e41ebbe61..57df3481e 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -1,120 +1,115 @@ -/* - * Copyright 2015 - 2022 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.api.resource; - -import org.traccar.api.BaseObjectResource; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.helper.LogAction; -import org.traccar.helper.model.UserUtil; -import org.traccar.model.ManagedUser; -import org.traccar.model.Permission; -import org.traccar.model.User; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.util.Collection; -import java.util.Date; - -@Path("users") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class UserResource extends BaseObjectResource { - - @Inject - private Config config; - - public UserResource() { - super(User.class); - } - - @GET - public Collection get(@QueryParam("userId") long userId) throws StorageException { - if (userId > 0) { - permissionsService.checkUser(getUserId(), userId); - return storage.getObjects(baseClass, new Request( - new Columns.All(), - new Condition.Permission(User.class, userId, ManagedUser.class).excludeGroups())); - } else if (permissionsService.notAdmin(getUserId())) { - return storage.getObjects(baseClass, new Request( - new Columns.All(), - new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())); - } else { - return storage.getObjects(baseClass, new Request(new Columns.All())); - } - } - - @Override - @PermitAll - @POST - public Response add(User entity) throws StorageException { - User currentUser = getUserId() > 0 ? permissionsService.getUser(getUserId()) : null; - if (currentUser == null || !currentUser.getAdministrator()) { - permissionsService.checkUserUpdate(getUserId(), new User(), entity); - if (currentUser != null && currentUser.getUserLimit() != 0) { - int userLimit = currentUser.getUserLimit(); - if (userLimit > 0) { - int userCount = storage.getObjects(baseClass, new Request( - new Columns.All(), - new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())) - .size(); - if (userCount >= userLimit) { - throw new SecurityException("Manager user limit reached"); - } - } - } else { - if (!permissionsService.getServer().getRegistration()) { - throw new SecurityException("Registration disabled"); - } - entity.setDeviceLimit(config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); - int expirationDays = config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); - if (expirationDays > 0) { - entity.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L)); - } - } - } - - if (UserUtil.isEmpty(storage)) { - entity.setAdministrator(true); - } - - entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); - storage.updateObject(entity, new Request( - new Columns.Include("hashedPassword", "salt"), - new Condition.Equals("id", entity.getId()))); - - LogAction.create(getUserId(), entity); - - if (currentUser != null && currentUser.getUserLimit() != 0) { - storage.addPermission(new Permission(User.class, getUserId(), ManagedUser.class, entity.getId())); - LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId()); - } - return Response.ok(entity).build(); - } - -} +/* + * Copyright 2015 - 2022 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.api.resource; + +import org.traccar.api.BaseObjectResource; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.helper.LogAction; +import org.traccar.helper.model.UserUtil; +import org.traccar.model.ManagedUser; +import org.traccar.model.Permission; +import org.traccar.model.User; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.annotation.security.PermitAll; +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.Collection; + +@Path("users") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class UserResource extends BaseObjectResource { + + @Inject + private Config config; + + public UserResource() { + super(User.class); + } + + @GET + public Collection get(@QueryParam("userId") long userId) throws StorageException { + if (userId > 0) { + permissionsService.checkUser(getUserId(), userId); + return storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, userId, ManagedUser.class).excludeGroups())); + } else if (permissionsService.notAdmin(getUserId())) { + return storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())); + } else { + return storage.getObjects(baseClass, new Request(new Columns.All())); + } + } + + @Override + @PermitAll + @POST + public Response add(User entity) throws StorageException { + User currentUser = getUserId() > 0 ? permissionsService.getUser(getUserId()) : null; + if (currentUser == null || !currentUser.getAdministrator()) { + permissionsService.checkUserUpdate(getUserId(), new User(), entity); + if (currentUser != null && currentUser.getUserLimit() != 0) { + int userLimit = currentUser.getUserLimit(); + if (userLimit > 0) { + int userCount = storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())) + .size(); + if (userCount >= userLimit) { + throw new SecurityException("Manager user limit reached"); + } + } + } else { + if (!permissionsService.getServer().getRegistration()) { + throw new SecurityException("Registration disabled"); + } + UserUtil.setUserDefaults(entity, config); + } + } + + if (UserUtil.isEmpty(storage)) { + entity.setAdministrator(true); + } + + entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); + storage.updateObject(entity, new Request( + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", entity.getId()))); + + LogAction.create(getUserId(), entity); + + if (currentUser != null && currentUser.getUserLimit() != 0) { + storage.addPermission(new Permission(User.class, getUserId(), ManagedUser.class, entity.getId())); + LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId()); + } + return Response.ok(entity).build(); + } + +} diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 7b51667c8..99539e50d 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -1,119 +1,123 @@ -/* - * Copyright 2022 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.api.security; - -import org.traccar.api.signature.TokenManager; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.LdapProvider; -import org.traccar.model.User; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.io.IOException; -import java.security.GeneralSecurityException; - -@Singleton -public class LoginService { - - private final Storage storage; - private final TokenManager tokenManager; - private final LdapProvider ldapProvider; - - private final String serviceAccountToken; - private final boolean forceLdap; - - @Inject - public LoginService( - Config config, Storage storage, TokenManager tokenManager, @Nullable LdapProvider ldapProvider) { - this.storage = storage; - this.tokenManager = tokenManager; - this.ldapProvider = ldapProvider; - serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN); - forceLdap = config.getBoolean(Keys.LDAP_FORCE); - } - - public User login(String token) throws StorageException, GeneralSecurityException, IOException { - if (serviceAccountToken != null && serviceAccountToken.equals(token)) { - return new ServiceAccountUser(); - } - long userId = tokenManager.verifyToken(token); - User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", userId))); - if (user != null) { - checkUserEnabled(user); - } - return user; - } - - public User login(String email, String password) throws StorageException { - email = email.trim(); - User user = storage.getObject(User.class, new Request( - new Columns.All(), - new Condition.Or( - new Condition.Equals("email", email), - new Condition.Equals("login", email)))); - if (user != null) { - if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) - || !forceLdap && user.isPasswordValid(password)) { - checkUserEnabled(user); - return user; - } - } else { - if (ldapProvider != null && ldapProvider.login(email, password)) { - user = ldapProvider.getUser(email); - user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); - checkUserEnabled(user); - return user; - } - } - return null; - } - - public User login(String email, String name, Boolean administrator) throws StorageException { - User user = storage.getObject(User.class, new Request( - new Columns.All(), - new Condition.Equals("email", email))); - - if (user != null) { - checkUserEnabled(user); - return user; - } else { - user = new User(); - user.setName(name); - user.setEmail(email); - user.setFixedEmail(true); - user.setAdministrator(administrator); - user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); - checkUserEnabled(user); - return user; - } - } - - private void checkUserEnabled(User user) throws SecurityException { - if (user == null) { - throw new SecurityException("Unknown account"); - } - user.checkDisabled(); - } - -} +/* + * Copyright 2022 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.api.security; + +import org.traccar.api.signature.TokenManager; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.LdapProvider; +import org.traccar.helper.model.UserUtil; +import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.IOException; +import java.security.GeneralSecurityException; + +@Singleton +public class LoginService { + + private final Config config; + private final Storage storage; + private final TokenManager tokenManager; + private final LdapProvider ldapProvider; + + private final String serviceAccountToken; + private final boolean forceLdap; + + @Inject + public LoginService( + Config config, Storage storage, TokenManager tokenManager, @Nullable LdapProvider ldapProvider) { + this.storage = storage; + this.config = config; + this.tokenManager = tokenManager; + this.ldapProvider = ldapProvider; + serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN); + forceLdap = config.getBoolean(Keys.LDAP_FORCE); + } + + public User login(String token) throws StorageException, GeneralSecurityException, IOException { + if (serviceAccountToken != null && serviceAccountToken.equals(token)) { + return new ServiceAccountUser(); + } + long userId = tokenManager.verifyToken(token); + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", userId))); + if (user != null) { + checkUserEnabled(user); + } + return user; + } + + public User login(String email, String password) throws StorageException { + email = email.trim(); + User user = storage.getObject(User.class, new Request( + new Columns.All(), + new Condition.Or( + new Condition.Equals("email", email), + new Condition.Equals("login", email)))); + if (user != null) { + if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) + || !forceLdap && user.isPasswordValid(password)) { + checkUserEnabled(user); + return user; + } + } else { + if (ldapProvider != null && ldapProvider.login(email, password)) { + user = ldapProvider.getUser(email); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + checkUserEnabled(user); + return user; + } + } + return null; + } + + public User login(String email, String name, Boolean administrator) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.All(), + new Condition.Equals("email", email))); + + if (user != null) { + checkUserEnabled(user); + return user; + } else { + user = new User(); + UserUtil.setUserDefaults(user, config); + user.setName(name); + user.setEmail(email); + user.setFixedEmail(true); + user.setAdministrator(administrator); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + checkUserEnabled(user); + return user; + } + } + + private void checkUserEnabled(User user) throws SecurityException { + if (user == null) { + throw new SecurityException("Unknown account"); + } + user.checkDisabled(); + } + +} diff --git a/src/main/java/org/traccar/helper/model/UserUtil.java b/src/main/java/org/traccar/helper/model/UserUtil.java index 9f93afeae..0dc355114 100644 --- a/src/main/java/org/traccar/helper/model/UserUtil.java +++ b/src/main/java/org/traccar/helper/model/UserUtil.java @@ -1,68 +1,78 @@ -/* - * Copyright 2022 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.helper.model; - -import org.traccar.model.Server; -import org.traccar.model.User; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Order; -import org.traccar.storage.query.Request; - -import java.util.TimeZone; - -public final class UserUtil { - - private UserUtil() { - } - - public static boolean isEmpty(Storage storage) throws StorageException { - return storage.getObjects(User.class, new Request( - new Columns.Include("id"), - new Order("id", false, 1))).isEmpty(); - } - - public static String getDistanceUnit(Server server, User user) { - return lookupStringAttribute(server, user, "distanceUnit", "km"); - } - - public static String getSpeedUnit(Server server, User user) { - return lookupStringAttribute(server, user, "speedUnit", "kn"); - } - - public static String getVolumeUnit(Server server, User user) { - return lookupStringAttribute(server, user, "volumeUnit", "ltr"); - } - - public static TimeZone getTimezone(Server server, User user) { - String timezone = lookupStringAttribute(server, user, "timezone", null); - return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); - } - - private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) { - String preference; - String serverPreference = server.getString(key); - String userPreference = user.getString(key); - if (server.getForceSettings()) { - preference = serverPreference != null ? serverPreference : userPreference; - } else { - preference = userPreference != null ? userPreference : serverPreference; - } - return preference != null ? preference : defaultValue; - } - -} +/* + * Copyright 2022 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.helper.model; + +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Server; +import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; + +import java.util.Date; +import java.util.TimeZone; + +public final class UserUtil { + + private UserUtil() { + } + + public static boolean isEmpty(Storage storage) throws StorageException { + return storage.getObjects(User.class, new Request( + new Columns.Include("id"), + new Order("id", false, 1))).isEmpty(); + } + + public static String getDistanceUnit(Server server, User user) { + return lookupStringAttribute(server, user, "distanceUnit", "km"); + } + + public static String getSpeedUnit(Server server, User user) { + return lookupStringAttribute(server, user, "speedUnit", "kn"); + } + + public static String getVolumeUnit(Server server, User user) { + return lookupStringAttribute(server, user, "volumeUnit", "ltr"); + } + + public static TimeZone getTimezone(Server server, User user) { + String timezone = lookupStringAttribute(server, user, "timezone", null); + return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); + } + + private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) { + String preference; + String serverPreference = server.getString(key); + String userPreference = user.getString(key); + if (server.getForceSettings()) { + preference = serverPreference != null ? serverPreference : userPreference; + } else { + preference = userPreference != null ? userPreference : serverPreference; + } + return preference != null ? preference : defaultValue; + } + + public static void setUserDefaults(User user, Config config) { + user.setDeviceLimit(config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); + int expirationDays = config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); + if (expirationDays > 0) { + user.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L)); + } + } +} diff --git a/traccar-web b/traccar-web index 506dd66b7..87e9c7dd5 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 506dd66b793803a24a2872e242482f263087df52 +Subproject commit 87e9c7dd5159c1d08368bfafa30fed9ae811933c -- cgit v1.2.3 From c6de74b4bb0f116b0fcbbb65b20296970597b652 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 17:39:06 +0100 Subject: Fixing my line endings, thanks Windows --- .../org/traccar/api/resource/SessionResource.java | 376 +- .../org/traccar/api/resource/UserResource.java | 230 +- .../org/traccar/api/security/LoginService.java | 246 +- .../java/org/traccar/database/OpenIdProvider.java | 326 +- .../java/org/traccar/helper/model/UserUtil.java | 156 +- swagger.json | 7052 ++++++++++---------- 6 files changed, 4193 insertions(+), 4193 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 8240a8a6f..94a6a4595 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -1,188 +1,188 @@ -/* - * Copyright 2015 - 2022 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.api.resource; - -import org.traccar.api.BaseResource; -import org.traccar.api.security.LoginService; -import org.traccar.api.signature.TokenManager; -import org.traccar.database.OpenIdProvider; -import org.traccar.helper.DataConverter; -import org.traccar.helper.LogAction; -import org.traccar.helper.ServletHelper; -import org.traccar.model.User; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import com.nimbusds.oauth2.sdk.ParseException; -import javax.annotation.Nullable; -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.io.IOException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.util.Date; -import java.net.URI; - -@Path("session") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_FORM_URLENCODED) -public class SessionResource extends BaseResource { - - public static final String USER_ID_KEY = "userId"; - public static final String USER_COOKIE_KEY = "user"; - public static final String PASS_COOKIE_KEY = "password"; - - @Inject - private LoginService loginService; - - @Inject - @Nullable - private OpenIdProvider openIdProvider; - - @Inject - private TokenManager tokenManager; - - @Context - private HttpServletRequest request; - - @PermitAll - @GET - public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException { - - if (token != null) { - User user = loginService.login(token); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } - } - - Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); - if (userId == null) { - - Cookie[] cookies = request.getCookies(); - String email = null, password = null; - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals(USER_COOKIE_KEY)) { - byte[] emailBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); - email = new String(emailBytes, StandardCharsets.UTF_8); - } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { - byte[] passwordBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); - password = new String(passwordBytes, StandardCharsets.UTF_8); - } - } - } - if (email != null && password != null) { - User user = loginService.login(email, password); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } - } - - } else { - - User user = permissionsService.getUser(userId); - if (user != null) { - return user; - } - - } - - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); - } - - @Path("{id}") - @GET - public User get(@PathParam("id") long userId) throws StorageException { - permissionsService.checkUser(getUserId(), userId); - User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", userId))); - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } - - @PermitAll - @POST - public User add( - @FormParam("email") String email, @FormParam("password") String password) throws StorageException { - User user = loginService.login(email, password); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - return user; - } else { - LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request)); - throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); - } - } - - @DELETE - public Response remove() { - LogAction.logout(getUserId(), ServletHelper.retrieveRemoteAddress(request)); - request.getSession().removeAttribute(USER_ID_KEY); - return Response.noContent().build(); - } - - @Path("token") - @POST - public String requestToken( - @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { - return tokenManager.generateToken(getUserId(), expiration); - } - - @PermitAll - @Path("openid/auth") - @GET - public Response openIdAuth() throws IOException { - return Response.seeOther(openIdProvider.createAuthUri()).build(); - } - - @PermitAll - @Path("openid/callback") - @GET - public Response requestToken() throws IOException, StorageException, ParseException, GeneralSecurityException { - StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString()); - String queryString = request.getQueryString(); - String requestUri = requestUrl.append('?').append(queryString).toString(); - - return Response.seeOther(openIdProvider.handleCallback(URI.create(requestUri), request)).build(); - } -} +/* + * Copyright 2015 - 2022 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.api.resource; + +import org.traccar.api.BaseResource; +import org.traccar.api.security.LoginService; +import org.traccar.api.signature.TokenManager; +import org.traccar.database.OpenIdProvider; +import org.traccar.helper.DataConverter; +import org.traccar.helper.LogAction; +import org.traccar.helper.ServletHelper; +import org.traccar.model.User; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import com.nimbusds.oauth2.sdk.ParseException; +import javax.annotation.Nullable; +import javax.annotation.security.PermitAll; +import javax.inject.Inject; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.net.URI; + +@Path("session") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_FORM_URLENCODED) +public class SessionResource extends BaseResource { + + public static final String USER_ID_KEY = "userId"; + public static final String USER_COOKIE_KEY = "user"; + public static final String PASS_COOKIE_KEY = "password"; + + @Inject + private LoginService loginService; + + @Inject + @Nullable + private OpenIdProvider openIdProvider; + + @Inject + private TokenManager tokenManager; + + @Context + private HttpServletRequest request; + + @PermitAll + @GET + public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException { + + if (token != null) { + User user = loginService.login(token); + if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } + } + + Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); + if (userId == null) { + + Cookie[] cookies = request.getCookies(); + String email = null, password = null; + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals(USER_COOKIE_KEY)) { + byte[] emailBytes = DataConverter.parseBase64( + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); + email = new String(emailBytes, StandardCharsets.UTF_8); + } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { + byte[] passwordBytes = DataConverter.parseBase64( + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); + password = new String(passwordBytes, StandardCharsets.UTF_8); + } + } + } + if (email != null && password != null) { + User user = loginService.login(email, password); + if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } + } + + } else { + + User user = permissionsService.getUser(userId); + if (user != null) { + return user; + } + + } + + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); + } + + @Path("{id}") + @GET + public User get(@PathParam("id") long userId) throws StorageException { + permissionsService.checkUser(getUserId(), userId); + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", userId))); + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } + + @PermitAll + @POST + public User add( + @FormParam("email") String email, @FormParam("password") String password) throws StorageException { + User user = loginService.login(email, password); + if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } else { + LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request)); + throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); + } + } + + @DELETE + public Response remove() { + LogAction.logout(getUserId(), ServletHelper.retrieveRemoteAddress(request)); + request.getSession().removeAttribute(USER_ID_KEY); + return Response.noContent().build(); + } + + @Path("token") + @POST + public String requestToken( + @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { + return tokenManager.generateToken(getUserId(), expiration); + } + + @PermitAll + @Path("openid/auth") + @GET + public Response openIdAuth() throws IOException { + return Response.seeOther(openIdProvider.createAuthUri()).build(); + } + + @PermitAll + @Path("openid/callback") + @GET + public Response requestToken() throws IOException, StorageException, ParseException, GeneralSecurityException { + StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString()); + String queryString = request.getQueryString(); + String requestUri = requestUrl.append('?').append(queryString).toString(); + + return Response.seeOther(openIdProvider.handleCallback(URI.create(requestUri), request)).build(); + } +} diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 57df3481e..1c58cec3c 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -1,115 +1,115 @@ -/* - * Copyright 2015 - 2022 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.api.resource; - -import org.traccar.api.BaseObjectResource; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.helper.LogAction; -import org.traccar.helper.model.UserUtil; -import org.traccar.model.ManagedUser; -import org.traccar.model.Permission; -import org.traccar.model.User; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.util.Collection; - -@Path("users") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class UserResource extends BaseObjectResource { - - @Inject - private Config config; - - public UserResource() { - super(User.class); - } - - @GET - public Collection get(@QueryParam("userId") long userId) throws StorageException { - if (userId > 0) { - permissionsService.checkUser(getUserId(), userId); - return storage.getObjects(baseClass, new Request( - new Columns.All(), - new Condition.Permission(User.class, userId, ManagedUser.class).excludeGroups())); - } else if (permissionsService.notAdmin(getUserId())) { - return storage.getObjects(baseClass, new Request( - new Columns.All(), - new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())); - } else { - return storage.getObjects(baseClass, new Request(new Columns.All())); - } - } - - @Override - @PermitAll - @POST - public Response add(User entity) throws StorageException { - User currentUser = getUserId() > 0 ? permissionsService.getUser(getUserId()) : null; - if (currentUser == null || !currentUser.getAdministrator()) { - permissionsService.checkUserUpdate(getUserId(), new User(), entity); - if (currentUser != null && currentUser.getUserLimit() != 0) { - int userLimit = currentUser.getUserLimit(); - if (userLimit > 0) { - int userCount = storage.getObjects(baseClass, new Request( - new Columns.All(), - new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())) - .size(); - if (userCount >= userLimit) { - throw new SecurityException("Manager user limit reached"); - } - } - } else { - if (!permissionsService.getServer().getRegistration()) { - throw new SecurityException("Registration disabled"); - } - UserUtil.setUserDefaults(entity, config); - } - } - - if (UserUtil.isEmpty(storage)) { - entity.setAdministrator(true); - } - - entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); - storage.updateObject(entity, new Request( - new Columns.Include("hashedPassword", "salt"), - new Condition.Equals("id", entity.getId()))); - - LogAction.create(getUserId(), entity); - - if (currentUser != null && currentUser.getUserLimit() != 0) { - storage.addPermission(new Permission(User.class, getUserId(), ManagedUser.class, entity.getId())); - LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId()); - } - return Response.ok(entity).build(); - } - -} +/* + * Copyright 2015 - 2022 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.api.resource; + +import org.traccar.api.BaseObjectResource; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.helper.LogAction; +import org.traccar.helper.model.UserUtil; +import org.traccar.model.ManagedUser; +import org.traccar.model.Permission; +import org.traccar.model.User; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.annotation.security.PermitAll; +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.Collection; + +@Path("users") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class UserResource extends BaseObjectResource { + + @Inject + private Config config; + + public UserResource() { + super(User.class); + } + + @GET + public Collection get(@QueryParam("userId") long userId) throws StorageException { + if (userId > 0) { + permissionsService.checkUser(getUserId(), userId); + return storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, userId, ManagedUser.class).excludeGroups())); + } else if (permissionsService.notAdmin(getUserId())) { + return storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())); + } else { + return storage.getObjects(baseClass, new Request(new Columns.All())); + } + } + + @Override + @PermitAll + @POST + public Response add(User entity) throws StorageException { + User currentUser = getUserId() > 0 ? permissionsService.getUser(getUserId()) : null; + if (currentUser == null || !currentUser.getAdministrator()) { + permissionsService.checkUserUpdate(getUserId(), new User(), entity); + if (currentUser != null && currentUser.getUserLimit() != 0) { + int userLimit = currentUser.getUserLimit(); + if (userLimit > 0) { + int userCount = storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())) + .size(); + if (userCount >= userLimit) { + throw new SecurityException("Manager user limit reached"); + } + } + } else { + if (!permissionsService.getServer().getRegistration()) { + throw new SecurityException("Registration disabled"); + } + UserUtil.setUserDefaults(entity, config); + } + } + + if (UserUtil.isEmpty(storage)) { + entity.setAdministrator(true); + } + + entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); + storage.updateObject(entity, new Request( + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", entity.getId()))); + + LogAction.create(getUserId(), entity); + + if (currentUser != null && currentUser.getUserLimit() != 0) { + storage.addPermission(new Permission(User.class, getUserId(), ManagedUser.class, entity.getId())); + LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId()); + } + return Response.ok(entity).build(); + } + +} diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 99539e50d..d92f7ce15 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -1,123 +1,123 @@ -/* - * Copyright 2022 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.api.security; - -import org.traccar.api.signature.TokenManager; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.LdapProvider; -import org.traccar.helper.model.UserUtil; -import org.traccar.model.User; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.io.IOException; -import java.security.GeneralSecurityException; - -@Singleton -public class LoginService { - - private final Config config; - private final Storage storage; - private final TokenManager tokenManager; - private final LdapProvider ldapProvider; - - private final String serviceAccountToken; - private final boolean forceLdap; - - @Inject - public LoginService( - Config config, Storage storage, TokenManager tokenManager, @Nullable LdapProvider ldapProvider) { - this.storage = storage; - this.config = config; - this.tokenManager = tokenManager; - this.ldapProvider = ldapProvider; - serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN); - forceLdap = config.getBoolean(Keys.LDAP_FORCE); - } - - public User login(String token) throws StorageException, GeneralSecurityException, IOException { - if (serviceAccountToken != null && serviceAccountToken.equals(token)) { - return new ServiceAccountUser(); - } - long userId = tokenManager.verifyToken(token); - User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", userId))); - if (user != null) { - checkUserEnabled(user); - } - return user; - } - - public User login(String email, String password) throws StorageException { - email = email.trim(); - User user = storage.getObject(User.class, new Request( - new Columns.All(), - new Condition.Or( - new Condition.Equals("email", email), - new Condition.Equals("login", email)))); - if (user != null) { - if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) - || !forceLdap && user.isPasswordValid(password)) { - checkUserEnabled(user); - return user; - } - } else { - if (ldapProvider != null && ldapProvider.login(email, password)) { - user = ldapProvider.getUser(email); - user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); - checkUserEnabled(user); - return user; - } - } - return null; - } - - public User login(String email, String name, Boolean administrator) throws StorageException { - User user = storage.getObject(User.class, new Request( - new Columns.All(), - new Condition.Equals("email", email))); - - if (user != null) { - checkUserEnabled(user); - return user; - } else { - user = new User(); - UserUtil.setUserDefaults(user, config); - user.setName(name); - user.setEmail(email); - user.setFixedEmail(true); - user.setAdministrator(administrator); - user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); - checkUserEnabled(user); - return user; - } - } - - private void checkUserEnabled(User user) throws SecurityException { - if (user == null) { - throw new SecurityException("Unknown account"); - } - user.checkDisabled(); - } - -} +/* + * Copyright 2022 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.api.security; + +import org.traccar.api.signature.TokenManager; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.LdapProvider; +import org.traccar.helper.model.UserUtil; +import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.IOException; +import java.security.GeneralSecurityException; + +@Singleton +public class LoginService { + + private final Config config; + private final Storage storage; + private final TokenManager tokenManager; + private final LdapProvider ldapProvider; + + private final String serviceAccountToken; + private final boolean forceLdap; + + @Inject + public LoginService( + Config config, Storage storage, TokenManager tokenManager, @Nullable LdapProvider ldapProvider) { + this.storage = storage; + this.config = config; + this.tokenManager = tokenManager; + this.ldapProvider = ldapProvider; + serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN); + forceLdap = config.getBoolean(Keys.LDAP_FORCE); + } + + public User login(String token) throws StorageException, GeneralSecurityException, IOException { + if (serviceAccountToken != null && serviceAccountToken.equals(token)) { + return new ServiceAccountUser(); + } + long userId = tokenManager.verifyToken(token); + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", userId))); + if (user != null) { + checkUserEnabled(user); + } + return user; + } + + public User login(String email, String password) throws StorageException { + email = email.trim(); + User user = storage.getObject(User.class, new Request( + new Columns.All(), + new Condition.Or( + new Condition.Equals("email", email), + new Condition.Equals("login", email)))); + if (user != null) { + if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) + || !forceLdap && user.isPasswordValid(password)) { + checkUserEnabled(user); + return user; + } + } else { + if (ldapProvider != null && ldapProvider.login(email, password)) { + user = ldapProvider.getUser(email); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + checkUserEnabled(user); + return user; + } + } + return null; + } + + public User login(String email, String name, Boolean administrator) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.All(), + new Condition.Equals("email", email))); + + if (user != null) { + checkUserEnabled(user); + return user; + } else { + user = new User(); + UserUtil.setUserDefaults(user, config); + user.setName(name); + user.setEmail(email); + user.setFixedEmail(true); + user.setAdministrator(administrator); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + checkUserEnabled(user); + return user; + } + } + + private void checkUserEnabled(User user) throws SecurityException { + if (user == null) { + throw new SecurityException("Unknown account"); + } + user.checkDisabled(); + } + +} diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 22e5d6b50..5e5c54523 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -1,163 +1,163 @@ -/* - * Copyright 2023 Daniel Raper (me@danr.uk) - * - * 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.database; - -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.api.resource.SessionResource; -import org.traccar.api.security.LoginService; -import org.traccar.model.User; -import org.traccar.storage.StorageException; -import org.traccar.helper.LogAction; -import org.traccar.helper.ServletHelper; - -import java.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; -import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import com.google.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.nimbusds.oauth2.sdk.http.HTTPResponse; -import com.nimbusds.oauth2.sdk.AuthorizationCode; -import com.nimbusds.oauth2.sdk.ResponseType; -import com.nimbusds.oauth2.sdk.Scope; -import com.nimbusds.oauth2.sdk.AuthorizationGrant; -import com.nimbusds.oauth2.sdk.TokenRequest; -import com.nimbusds.oauth2.sdk.TokenResponse; -import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; -import com.nimbusds.oauth2.sdk.ParseException; -import com.nimbusds.oauth2.sdk.AuthorizationResponse; -import com.nimbusds.oauth2.sdk.auth.Secret; -import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; -import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; -import com.nimbusds.oauth2.sdk.token.BearerAccessToken; -import com.nimbusds.oauth2.sdk.id.State; -import com.nimbusds.oauth2.sdk.id.ClientID; -import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; -import com.nimbusds.openid.connect.sdk.Nonce; -import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; -import com.nimbusds.openid.connect.sdk.UserInfoResponse; -import com.nimbusds.openid.connect.sdk.UserInfoRequest; -import com.nimbusds.openid.connect.sdk.AuthenticationRequest; - -import com.nimbusds.openid.connect.sdk.claims.UserInfo; - -public class OpenIdProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdProvider.class); - - public final Boolean force; - private final ClientID clientId; - private final ClientAuthentication clientAuth; - private URI callbackUrl; - private URI authUrl; - private URI tokenUrl; - private URI userInfoUrl; - private URI baseUrl; - private final String adminGroup; - - private LoginService loginService; - - @Inject - public OpenIdProvider(Config config, LoginService loginService) { - this.loginService = loginService; - - force = config.getBoolean(Keys.OPENID_FORCE); - clientId = new ClientID(config.getString(Keys.OPENID_CLIENTID)); - clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENTSECRET))); - - try { - callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); - authUrl = new URI(config.getString(Keys.OPENID_AUTHURL, "")); - tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); - userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); - baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - } catch(URISyntaxException error) { - LOGGER.error("Invalid URIs provided in OpenID configuration"); - } - - adminGroup = config.getString(Keys.OPENID_ADMINGROUP); - } - - public URI createAuthUri() { - AuthenticationRequest.Builder request = new AuthenticationRequest.Builder( - new ResponseType("code"), - new Scope("openid", "profile", "email", "groups"), - clientId, - callbackUrl); - - return request.endpointURI(authUrl) - .state(new State()) - .build() - .toURI(); - } - - private OIDCTokenResponse getToken(AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { - AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); - TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); - - HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send(); - TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse); - if (!token.indicatesSuccess()) { - throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); - } - - return (OIDCTokenResponse) token.toSuccessResponse(); - } - - private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException { - HTTPResponse httpResponse = new UserInfoRequest(userInfoUrl, token) - .toHTTPRequest() - .send(); - - UserInfoResponse userInfoResponse = UserInfoResponse.parse(httpResponse); - - if (!userInfoResponse.indicatesSuccess()) { - throw new GeneralSecurityException("Failed to access OpenID Connect user info endpoint. Please contact your administrator."); - } - - return userInfoResponse.toSuccessResponse().getUserInfo(); - } - - public URI handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, GeneralSecurityException { - AuthorizationResponse response = AuthorizationResponse.parse(requestUri); - - if (!response.indicatesSuccess()) { - throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); - } - - AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); - - if (authCode == null) { - throw new GeneralSecurityException( "Malformed OpenID callback."); - } - - OIDCTokenResponse tokens = getToken(authCode); - - BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); - - UserInfo userInfo = getUserInfo(bearerToken); - - User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), userInfo.getStringListClaim("groups").contains(adminGroup)); - - request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - - return baseUrl; - } -} +/* + * Copyright 2023 Daniel Raper (me@danr.uk) + * + * 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.database; + +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.api.resource.SessionResource; +import org.traccar.api.security.LoginService; +import org.traccar.model.User; +import org.traccar.storage.StorageException; +import org.traccar.helper.LogAction; +import org.traccar.helper.ServletHelper; + +import java.net.URI; +import java.net.URISyntaxException; +import java.security.GeneralSecurityException; +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import com.google.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.nimbusds.oauth2.sdk.http.HTTPResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCode; +import com.nimbusds.oauth2.sdk.ResponseType; +import com.nimbusds.oauth2.sdk.Scope; +import com.nimbusds.oauth2.sdk.AuthorizationGrant; +import com.nimbusds.oauth2.sdk.TokenRequest; +import com.nimbusds.oauth2.sdk.TokenResponse; +import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; +import com.nimbusds.oauth2.sdk.ParseException; +import com.nimbusds.oauth2.sdk.AuthorizationResponse; +import com.nimbusds.oauth2.sdk.auth.Secret; +import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; +import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; +import com.nimbusds.oauth2.sdk.token.BearerAccessToken; +import com.nimbusds.oauth2.sdk.id.State; +import com.nimbusds.oauth2.sdk.id.ClientID; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; +import com.nimbusds.openid.connect.sdk.Nonce; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; +import com.nimbusds.openid.connect.sdk.UserInfoResponse; +import com.nimbusds.openid.connect.sdk.UserInfoRequest; +import com.nimbusds.openid.connect.sdk.AuthenticationRequest; + +import com.nimbusds.openid.connect.sdk.claims.UserInfo; + +public class OpenIdProvider { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdProvider.class); + + public final Boolean force; + private final ClientID clientId; + private final ClientAuthentication clientAuth; + private URI callbackUrl; + private URI authUrl; + private URI tokenUrl; + private URI userInfoUrl; + private URI baseUrl; + private final String adminGroup; + + private LoginService loginService; + + @Inject + public OpenIdProvider(Config config, LoginService loginService) { + this.loginService = loginService; + + force = config.getBoolean(Keys.OPENID_FORCE); + clientId = new ClientID(config.getString(Keys.OPENID_CLIENTID)); + clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENTSECRET))); + + try { + callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); + authUrl = new URI(config.getString(Keys.OPENID_AUTHURL, "")); + tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); + userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); + baseUrl = new URI(config.getString(Keys.WEB_URL, "")); + } catch(URISyntaxException error) { + LOGGER.error("Invalid URIs provided in OpenID configuration"); + } + + adminGroup = config.getString(Keys.OPENID_ADMINGROUP); + } + + public URI createAuthUri() { + AuthenticationRequest.Builder request = new AuthenticationRequest.Builder( + new ResponseType("code"), + new Scope("openid", "profile", "email", "groups"), + clientId, + callbackUrl); + + return request.endpointURI(authUrl) + .state(new State()) + .build() + .toURI(); + } + + private OIDCTokenResponse getToken(AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { + AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); + TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); + + HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send(); + TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse); + if (!token.indicatesSuccess()) { + throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); + } + + return (OIDCTokenResponse) token.toSuccessResponse(); + } + + private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException { + HTTPResponse httpResponse = new UserInfoRequest(userInfoUrl, token) + .toHTTPRequest() + .send(); + + UserInfoResponse userInfoResponse = UserInfoResponse.parse(httpResponse); + + if (!userInfoResponse.indicatesSuccess()) { + throw new GeneralSecurityException("Failed to access OpenID Connect user info endpoint. Please contact your administrator."); + } + + return userInfoResponse.toSuccessResponse().getUserInfo(); + } + + public URI handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, GeneralSecurityException { + AuthorizationResponse response = AuthorizationResponse.parse(requestUri); + + if (!response.indicatesSuccess()) { + throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); + } + + AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); + + if (authCode == null) { + throw new GeneralSecurityException( "Malformed OpenID callback."); + } + + OIDCTokenResponse tokens = getToken(authCode); + + BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); + + UserInfo userInfo = getUserInfo(bearerToken); + + User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), userInfo.getStringListClaim("groups").contains(adminGroup)); + + request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + + return baseUrl; + } +} diff --git a/src/main/java/org/traccar/helper/model/UserUtil.java b/src/main/java/org/traccar/helper/model/UserUtil.java index 0dc355114..4b1c404f9 100644 --- a/src/main/java/org/traccar/helper/model/UserUtil.java +++ b/src/main/java/org/traccar/helper/model/UserUtil.java @@ -1,78 +1,78 @@ -/* - * Copyright 2022 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.helper.model; - -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.model.Server; -import org.traccar.model.User; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Order; -import org.traccar.storage.query.Request; - -import java.util.Date; -import java.util.TimeZone; - -public final class UserUtil { - - private UserUtil() { - } - - public static boolean isEmpty(Storage storage) throws StorageException { - return storage.getObjects(User.class, new Request( - new Columns.Include("id"), - new Order("id", false, 1))).isEmpty(); - } - - public static String getDistanceUnit(Server server, User user) { - return lookupStringAttribute(server, user, "distanceUnit", "km"); - } - - public static String getSpeedUnit(Server server, User user) { - return lookupStringAttribute(server, user, "speedUnit", "kn"); - } - - public static String getVolumeUnit(Server server, User user) { - return lookupStringAttribute(server, user, "volumeUnit", "ltr"); - } - - public static TimeZone getTimezone(Server server, User user) { - String timezone = lookupStringAttribute(server, user, "timezone", null); - return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); - } - - private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) { - String preference; - String serverPreference = server.getString(key); - String userPreference = user.getString(key); - if (server.getForceSettings()) { - preference = serverPreference != null ? serverPreference : userPreference; - } else { - preference = userPreference != null ? userPreference : serverPreference; - } - return preference != null ? preference : defaultValue; - } - - public static void setUserDefaults(User user, Config config) { - user.setDeviceLimit(config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); - int expirationDays = config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); - if (expirationDays > 0) { - user.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L)); - } - } -} +/* + * Copyright 2022 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.helper.model; + +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Server; +import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; + +import java.util.Date; +import java.util.TimeZone; + +public final class UserUtil { + + private UserUtil() { + } + + public static boolean isEmpty(Storage storage) throws StorageException { + return storage.getObjects(User.class, new Request( + new Columns.Include("id"), + new Order("id", false, 1))).isEmpty(); + } + + public static String getDistanceUnit(Server server, User user) { + return lookupStringAttribute(server, user, "distanceUnit", "km"); + } + + public static String getSpeedUnit(Server server, User user) { + return lookupStringAttribute(server, user, "speedUnit", "kn"); + } + + public static String getVolumeUnit(Server server, User user) { + return lookupStringAttribute(server, user, "volumeUnit", "ltr"); + } + + public static TimeZone getTimezone(Server server, User user) { + String timezone = lookupStringAttribute(server, user, "timezone", null); + return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); + } + + private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) { + String preference; + String serverPreference = server.getString(key); + String userPreference = user.getString(key); + if (server.getForceSettings()) { + preference = serverPreference != null ? serverPreference : userPreference; + } else { + preference = userPreference != null ? userPreference : serverPreference; + } + return preference != null ? preference : defaultValue; + } + + public static void setUserDefaults(User user, Config config) { + user.setDeviceLimit(config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); + int expirationDays = config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); + if (expirationDays > 0) { + user.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L)); + } + } +} diff --git a/swagger.json b/swagger.json index 5a7349da8..cbdc9effd 100644 --- a/swagger.json +++ b/swagger.json @@ -1,3526 +1,3526 @@ -{ - "openapi": "3.0.1", - "info": { - "title": "Traccar", - "version": "5.6", - "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", - "contact": { - "name": "Traccar Support", - "url": "https://www.traccar.org/", - "email": "support@traccar.org" - }, - "license": { - "name": "Apache 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0.html" - } - }, - "servers": [ - { - "url": "https://demo.traccar.org/api", - "description": "Demo Server 1" - }, - { - "url": "https://demo2.traccar.org/api", - "description": "Demo Server 2" - }, - { - "url": "https://demo3.traccar.org/api", - "description": "Demo Server 3" - }, - { - "url": "https://demo4.traccar.org/api", - "description": "Demo Server 4" - }, - { - "url": "https://server.traccar.org/api", - "description": "Subscription Server" - }, - { - "url": "http://{host}:{port}/api", - "description": "Other Server", - "variables": { - "host": { - "default": "localhost" - }, - "port": { - "enum": [ - "8082", - "80" - ], - "default": "8082" - } - } - } - ], - "security": [ - { - "basicAuth": [] - } - ], - "tags": [ - { - "name": "Server", - "description": "Server information" - }, - { - "name": "Session", - "description": "User session management" - }, - { - "name": "Devices", - "description": "Device management" - }, - { - "name": "Groups", - "description": "Group management" - }, - { - "name": "Users", - "description": "User management" - }, - { - "name": "Permissions", - "description": "User permissions and other object linking" - }, - { - "name": "Positions", - "description": "Retrieving raw location information" - }, - { - "name": "Events", - "description": "Retrieving event information" - }, - { - "name": "Reports", - "description": "Reports generation" - }, - { - "name": "Notifications", - "description": "User notifications management" - }, - { - "name": "Geofences", - "description": "Geofence management" - }, - { - "name": "Commands", - "description": "Sending commands to devices and stored command management" - }, - { - "name": "Attributes", - "description": "Computed attributes management" - }, - { - "name": "Drivers", - "description": "Drivers management" - }, - { - "name": "Maintenance", - "description": "Maintenance management" - }, - { - "name": "Calendars", - "description": "Calendar management" - }, - { - "name": "Statistics", - "description": "Retrieving server statistics" - } - ], - "paths": { - "/commands": { - "get": { - "summary": "Fetch a list of Saved Commands", - "tags": [ - "Commands" - ], - "description": "Without params, it returns a list of Saved Commands the user has access to", - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Command" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Saved Command", - "tags": [ - "Commands" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/commands/{id}": { - "put": { - "summary": "Update a Saved Command", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Saved Command", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/commands/send": { - "get": { - "summary": "Fetch a list of Saved Commands supported by Device at the moment", - "description": "Return a list of saved commands linked to Device and its groups, filtered by current Device protocol support", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Command" - } - } - } - } - }, - "400": { - "description": "Could happen when the user doesn't have permission for the device", - "content": {} - } - } - }, - "post": { - "summary": "Dispatch commands to device", - "description": "Dispatch a new command or Saved Command if _body.id_ set", - "tags": [ - "Commands" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Command sent", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - }, - "202": { - "description": "Command queued", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - } - }, - "400": { - "description": "Could happen when the user doesn't have permission or an incorrect command _type_ for the device", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/commands/types": { - "get": { - "summary": "Fetch a list of available Commands for the Device or all possible Commands if Device ommited", - "tags": [ - "Commands" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "description": "Internal device identifier. Only works if device has already reported some locations", - "schema": { - "type": "integer" - } - }, - { - "name": "protocol", - "in": "query", - "description": "Protocol name. Can be used instead of device id", - "schema": { - "type": "string" - } - }, - { - "name": "textChannel", - "in": "query", - "description": "When `true` return SMS commands. If not specified or `false` return data commands", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CommandType" - } - } - } - } - }, - "400": { - "description": "Could happen when trying to fetch from a device the user does not have permission", - "content": {} - } - } - } - }, - "/devices": { - "get": { - "summary": "Fetch a list of Devices", - "description": "Without any params, returns a list of the user's devices", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "id", - "in": "query", - "description": "To fetch one or more devices. Multiple params can be passed like `id=31&id=42`", - "schema": { - "type": "integer" - } - }, - { - "name": "uniqueId", - "in": "query", - "description": "To fetch one or more devices. Multiple params can be passed like `uniqueId=333331&uniqieId=44442`", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Device" - } - } - } - } - }, - "400": { - "description": "No permission", - "content": {} - } - } - }, - "post": { - "summary": "Create a Device", - "tags": [ - "Devices" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/devices/{id}": { - "put": { - "summary": "Update a Device", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Device", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/devices/{id}/accumulators": { - "put": { - "summary": "Update total distance and hours of the Device", - "tags": [ - "Devices" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeviceAccumulators" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "No Content", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/groups": { - "get": { - "summary": "Fetch a list of Groups", - "description": "Without any params, returns a list of the Groups the user belongs to", - "tags": [ - "Groups" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Group" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Group", - "tags": [ - "Groups" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - } - }, - "400": { - "description": "No permission", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/groups/{id}": { - "put": { - "summary": "Update a Group", - "tags": [ - "Groups" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Group", - "tags": [ - "Groups" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/permissions": { - "post": { - "summary": "Link an Object to another Object", - "tags": [ - "Permissions" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "No Content", - "content": {} - }, - "400": { - "description": "No permission", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Unlink an Object from another Object", - "tags": [ - "Permissions" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "No Content", - "content": {} - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/positions": { - "get": { - "summary": "Fetches a list of Positions", - "description": "We strongly recommend using [Traccar WebSocket API](https://www.traccar.org/traccar-api/) instead of periodically polling positions endpoint. Without any params, it returns a list of last known positions for all the user's Devices. _from_ and _to_ fields are not required with _id_.", - "tags": [ - "Positions" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "description": "_deviceId_ is optional, but requires the _from_ and _to_ parameters when used", - "schema": { - "type": "integer" - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "id", - "in": "query", - "description": "To fetch one or more positions. Multiple params can be passed like `id=31&id=42`", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - }, - "text/csv": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - }, - "application/gpx+xml": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - } - } - } - } - } - }, - "/server": { - "get": { - "summary": "Fetch Server information", - "tags": [ - "Server" - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Server" - } - } - } - } - } - }, - "put": { - "summary": "Update Server information", - "tags": [ - "Server" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Server" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Server" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/session": { - "get": { - "summary": "Fetch Session information", - "tags": [ - "Session" - ], - "parameters": [ - { - "name": "token", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - }, - "404": { - "description": "Not Found", - "content": {} - } - } - }, - "post": { - "summary": "Create a new Session", - "tags": [ - "Session" - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "required": [ - "email", - "password" - ], - "properties": { - "email": { - "type": "string" - }, - "password": { - "type": "string", - "format": "password" - } - } - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": {} - } - } - }, - "delete": { - "summary": "Close the Session", - "tags": [ - "Session" - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/session/openid/auth": { - "get": { - "summary": "Fetch Session information", - "tags": [ - "Session" - ], - "parameters": [ - { - } - ], - "responses": { - "303": { - "description": "Redirect to OpenID Connect identity provider", - "content": { } - } - } - } - }, - "/session/openid/callback": { - "get": { - "summary": "OpenID Callback", - "tags": [ - "Session" - ], - "parameters": [ - { - } - ], - "responses": { - "303": { - "description": "Successful authentication, redirect to homepage", - "content": { } - } - } - } - }, - "/users": { - "get": { - "summary": "Fetch a list of Users", - "tags": [ - "Users" - ], - "parameters": [ - { - "name": "userId", - "in": "query", - "description": "Can only be used by admin or manager users", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/User" - } - } - } - } - }, - "400": { - "description": "No Permission", - "content": {} - } - } - }, - "post": { - "summary": "Create a User", - "tags": [ - "Users" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/users/{id}": { - "put": { - "summary": "Update a User", - "tags": [ - "Users" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a User", - "tags": [ - "Users" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/notifications": { - "get": { - "summary": "Fetch a list of Notifications", - "description": "Without params, it returns a list of Notifications the user has access to", - "tags": [ - "Notifications" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Notification" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Notification", - "tags": [ - "Notifications" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/notifications/{id}": { - "put": { - "summary": "Update a Notification", - "tags": [ - "Notifications" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Notification", - "tags": [ - "Notifications" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/notifications/types": { - "get": { - "summary": "Fetch a list of available Notification types", - "tags": [ - "Notifications" - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationType" - } - } - } - } - } - } - } - }, - "/notifications/test": { - "post": { - "summary": "Send test notification to current user via Email and SMS", - "tags": [ - "Notifications" - ], - "responses": { - "204": { - "description": "Successful sending", - "content": {} - }, - "400": { - "description": "Could happen if sending has failed", - "content": {} - } - } - } - }, - "/geofences": { - "get": { - "summary": "Fetch a list of Geofences", - "description": "Without params, it returns a list of Geofences the user has access to", - "tags": [ - "Geofences" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Geofence" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Geofence", - "tags": [ - "Geofences" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/geofences/{id}": { - "put": { - "summary": "Update a Geofence", - "tags": [ - "Geofences" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Geofence", - "tags": [ - "Geofences" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/events/{id}": { - "get": { - "tags": [ - "Events" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Event" - } - } - } - } - } - } - }, - "/reports/route": { - "get": { - "summary": "Fetch a list of Positions within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Position" - } - } - } - } - } - } - } - }, - "/reports/events": { - "get": { - "summary": "Fetch a list of Events within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "type", - "in": "query", - "description": "% can be used to return events of all types", - "style": "form", - "explode": false, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Event" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Event" - } - } - } - } - } - } - } - }, - "/reports/summary": { - "get": { - "summary": "Fetch a list of ReportSummary within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportSummary" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportSummary" - } - } - } - } - } - } - } - }, - "/reports/trips": { - "get": { - "summary": "Fetch a list of ReportTrips within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportTrips" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportTrips" - } - } - } - } - } - } - } - }, - "/reports/stops": { - "get": { - "summary": "Fetch a list of ReportStops within the time period for the Devices or Groups", - "description": "At least one _deviceId_ or one _groupId_ must be passed", - "tags": [ - "Reports" - ], - "parameters": [ - { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportStops" - } - } - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ReportStops" - } - } - } - } - } - } - } - }, - "/statistics": { - "get": { - "summary": "Fetch server Statistics", - "tags": [ - "Statistics" - ], - "parameters": [ - { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Statistics" - } - } - } - } - } - } - } - }, - "/calendars": { - "get": { - "summary": "Fetch a list of Calendars", - "description": "Without params, it returns a list of Calendars the user has access to", - "tags": [ - "Calendars" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Calendar" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Calendar", - "tags": [ - "Calendars" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/calendars/{id}": { - "put": { - "summary": "Update a Calendar", - "tags": [ - "Calendars" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Calendar", - "tags": [ - "Calendars" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/attributes/computed": { - "get": { - "summary": "Fetch a list of Attributes", - "description": "Without params, it returns a list of Attributes the user has access to", - "tags": [ - "Attributes" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Attribute" - } - } - } - } - } - } - }, - "post": { - "summary": "Create an Attribute", - "tags": [ - "Attributes" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/attributes/computed/{id}": { - "put": { - "summary": "Update an Attribute", - "tags": [ - "Attributes" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete an Attribute", - "tags": [ - "Attributes" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/drivers": { - "get": { - "summary": "Fetch a list of Drivers", - "description": "Without params, it returns a list of Drivers the user has access to", - "tags": [ - "Drivers" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Driver" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Driver", - "tags": [ - "Drivers" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/drivers/{id}": { - "put": { - "summary": "Update a Driver", - "tags": [ - "Drivers" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Driver", - "tags": [ - "Drivers" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - }, - "/maintenance": { - "get": { - "summary": "Fetch a list of Maintenance", - "description": "Without params, it returns a list of Maintenance the user has access to", - "tags": [ - "Maintenance" - ], - "parameters": [ - { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Maintenance" - } - } - } - } - } - } - }, - "post": { - "summary": "Create a Maintenance", - "tags": [ - "Maintenance" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - } - }, - "/maintenance/{id}": { - "put": { - "summary": "Update a Maintenance", - "tags": [ - "Maintenance" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "delete": { - "summary": "Delete a Maintenance", - "tags": [ - "Maintenance" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "content": {} - } - } - } - } - }, - "components": { - "schemas": { - "Position": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "deviceId": { - "type": "integer" - }, - "protocol": { - "type": "string" - }, - "deviceTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "fixTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "serverTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "outdated": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - }, - "latitude": { - "type": "number" - }, - "longitude": { - "type": "number" - }, - "altitude": { - "type": "number" - }, - "speed": { - "type": "number", - "description": "in knots" - }, - "course": { - "type": "number" - }, - "address": { - "type": "string" - }, - "accuracy": { - "type": "number" - }, - "network": { - "type": "object", - "properties": {} - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "User": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "email": { - "type": "string" - }, - "phone": { - "type": "string" - }, - "readonly": { - "type": "boolean" - }, - "administrator": { - "type": "boolean" - }, - "map": { - "type": "string" - }, - "latitude": { - "type": "number" - }, - "longitude": { - "type": "number" - }, - "zoom": { - "type": "integer" - }, - "password": { - "type": "string" - }, - "twelveHourFormat": { - "type": "boolean" - }, - "coordinateFormat": { - "type": "string" - }, - "disabled": { - "type": "boolean" - }, - "expirationTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "deviceLimit": { - "type": "integer" - }, - "userLimit": { - "type": "integer" - }, - "deviceReadonly": { - "type": "boolean" - }, - "limitCommands": { - "type": "boolean" - }, - "poiLayer": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Server": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "registration": { - "type": "boolean" - }, - "readonly": { - "type": "boolean" - }, - "deviceReadonly": { - "type": "boolean" - }, - "limitCommands": { - "type": "boolean" - }, - "map": { - "type": "string" - }, - "bingKey": { - "type": "string" - }, - "mapUrl": { - "type": "string" - }, - "poiLayer": { - "type": "string" - }, - "latitude": { - "type": "number" - }, - "longitude": { - "type": "number" - }, - "zoom": { - "type": "integer" - }, - "twelveHourFormat": { - "type": "boolean" - }, - "version": { - "type": "string" - }, - "forceSettings": { - "type": "boolean" - }, - "coordinateFormat": { - "type": "string" - }, - "openIdEnabled": { - "type": "boolean" - }, - "openIdForce": { - "type": "boolean" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Command": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "deviceId": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "type": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Device": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "uniqueId": { - "type": "string" - }, - "status": { - "type": "string" - }, - "disabled": { - "type": "boolean" - }, - "lastUpdate": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "positionId": { - "type": "integer" - }, - "groupId": { - "type": "integer" - }, - "phone": { - "type": "string" - }, - "model": { - "type": "string" - }, - "contact": { - "type": "string" - }, - "category": { - "type": "string" - }, - "geofenceIds": { - "type": "array", - "items": { - "type": "integer" - } - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Group": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "groupId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Permission": { - "type": "object", - "properties": { - "userId": { - "type": "integer", - "description": "User Id, can be only first parameter" - }, - "deviceId": { - "type": "integer", - "description": "Device Id, can be first parameter or second only in combination with userId" - }, - "groupId": { - "type": "integer", - "description": "Group Id, can be first parameter or second only in combination with userId" - }, - "geofenceId": { - "type": "integer", - "description": "Geofence Id, can be second parameter only" - }, - "notificationId": { - "type": "integer", - "description": "Notification Id, can be second parameter only" - }, - "calendarId": { - "type": "integer", - "description": "Calendar Id, can be second parameter only and only in combination with userId" - }, - "attributeId": { - "type": "integer", - "description": "Computed Attribute Id, can be second parameter only" - }, - "driverId": { - "type": "integer", - "description": "Driver Id, can be second parameter only" - }, - "managedUserId": { - "type": "integer", - "description": "User Id, can be second parameter only and only in combination with userId" - } - }, - "description": "This is a permission map that contain two object indexes. It is used to link/unlink objects. Order is important. Example: { deviceId:8, geofenceId: 16 }" - }, - "CommandType": { - "type": "object", - "properties": { - "type": { - "type": "string" - } - } - }, - "Geofence": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "area": { - "type": "string" - }, - "calendarId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Notification": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "always": { - "type": "boolean" - }, - "web": { - "type": "boolean" - }, - "mail": { - "type": "boolean" - }, - "sms": { - "type": "boolean" - }, - "calendarId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "NotificationType": { - "type": "object", - "properties": { - "type": { - "type": "string" - } - } - }, - "Event": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "eventTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "deviceId": { - "type": "integer" - }, - "positionId": { - "type": "integer" - }, - "geofenceId": { - "type": "integer" - }, - "maintenanceId": { - "type": "integer" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "ReportSummary": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "deviceName": { - "type": "string" - }, - "maxSpeed": { - "type": "number", - "description": "in knots" - }, - "averageSpeed": { - "type": "number", - "description": "in knots" - }, - "distance": { - "type": "number", - "description": "in meters" - }, - "spentFuel": { - "type": "number", - "description": "in liters" - }, - "engineHours": { - "type": "integer" - } - } - }, - "ReportTrips": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "deviceName": { - "type": "string" - }, - "maxSpeed": { - "type": "number", - "description": "in knots" - }, - "averageSpeed": { - "type": "number", - "description": "in knots" - }, - "distance": { - "type": "number", - "description": "in meters" - }, - "spentFuel": { - "type": "number", - "description": "in liters" - }, - "duration": { - "type": "integer" - }, - "startTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "startAddress": { - "type": "string" - }, - "startLat": { - "type": "number" - }, - "startLon": { - "type": "number" - }, - "endTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "endAddress": { - "type": "string" - }, - "endLat": { - "type": "number" - }, - "endLon": { - "type": "number" - }, - "driverUniqueId": { - "type": "integer" - }, - "driverName": { - "type": "string" - } - } - }, - "ReportStops": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "deviceName": { - "type": "string" - }, - "duration": { - "type": "integer" - }, - "startTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "address": { - "type": "string" - }, - "lat": { - "type": "number" - }, - "lon": { - "type": "number" - }, - "endTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "spentFuel": { - "type": "number", - "description": "in liters" - }, - "engineHours": { - "type": "integer" - } - } - }, - "Statistics": { - "type": "object", - "properties": { - "captureTime": { - "type": "string", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "format": "date-time" - }, - "activeUsers": { - "type": "integer" - }, - "activeDevices": { - "type": "integer" - }, - "requests": { - "type": "integer" - }, - "messagesReceived": { - "type": "integer" - }, - "messagesStored": { - "type": "integer" - } - } - }, - "DeviceAccumulators": { - "type": "object", - "properties": { - "deviceId": { - "type": "integer" - }, - "totalDistance": { - "type": "number", - "description": "in meters" - }, - "hours": { - "type": "number" - } - } - }, - "Calendar": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "data": { - "type": "string", - "description": "base64 encoded in iCalendar format" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Attribute": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "attribute": { - "type": "string" - }, - "expression": { - "type": "string" - }, - "type": { - "type": "string", - "description": "String|Number|Boolean" - } - } - }, - "Driver": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "uniqueId": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - }, - "Maintenance": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "type": { - "type": "string" - }, - "start": { - "type": "number" - }, - "period": { - "type": "number" - }, - "attributes": { - "type": "object", - "properties": {} - } - } - } - }, - "parameters": { - "entityId": { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer" - } - }, - "all": { - "name": "all", - "in": "query", - "description": "Can only be used by admins or managers to fetch all entities", - "schema": { - "type": "boolean" - } - }, - "refresh": { - "name": "refresh", - "in": "query", - "schema": { - "type": "boolean" - } - }, - "userId": { - "name": "userId", - "in": "query", - "description": "Standard users can use this only with their own _userId_", - "schema": { - "type": "integer" - } - }, - "deviceId": { - "name": "deviceId", - "in": "query", - "description": "Standard users can use this only with _deviceId_s, they have access to", - "schema": { - "type": "integer" - } - }, - "groupId": { - "name": "groupId", - "in": "query", - "description": "Standard users can use this only with _groupId_s, they have access to", - "schema": { - "type": "integer" - } - }, - "deviceIdArray": { - "name": "deviceId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - "groupIdArray": { - "name": "groupId", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "items": { - "type": "integer" - } - } - }, - "fromTime": { - "name": "from", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - }, - "toTime": { - "name": "to", - "in": "query", - "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", - "required": true, - "schema": { - "type": "string", - "format": "date-time" - } - } - }, - "requestBodies": { - "Device": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Device" - } - } - }, - "required": true - }, - "Permission": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Permission" - } - } - }, - "required": true - }, - "Group": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Group" - } - } - }, - "required": true - }, - "User": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - }, - "required": true - }, - "Geofence": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Geofence" - } - } - }, - "required": true - }, - "Calendar": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Calendar" - } - } - }, - "required": true - }, - "Attribute": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Attribute" - } - } - }, - "required": true - }, - "Driver": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Driver" - } - } - }, - "required": true - }, - "Command": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Command" - } - } - }, - "required": true - }, - "Notification": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Notification" - } - } - }, - "required": true - }, - "Maintenance": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Maintenance" - } - } - }, - "required": true - } - }, - "securitySchemes": { - "basicAuth": { - "type": "http", - "description": "Basic HTTP authorization with _email_ and _password_", - "scheme": "basic" - } - } - } -} +{ + "openapi": "3.0.1", + "info": { + "title": "Traccar", + "version": "5.6", + "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", + "contact": { + "name": "Traccar Support", + "url": "https://www.traccar.org/", + "email": "support@traccar.org" + }, + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "https://demo.traccar.org/api", + "description": "Demo Server 1" + }, + { + "url": "https://demo2.traccar.org/api", + "description": "Demo Server 2" + }, + { + "url": "https://demo3.traccar.org/api", + "description": "Demo Server 3" + }, + { + "url": "https://demo4.traccar.org/api", + "description": "Demo Server 4" + }, + { + "url": "https://server.traccar.org/api", + "description": "Subscription Server" + }, + { + "url": "http://{host}:{port}/api", + "description": "Other Server", + "variables": { + "host": { + "default": "localhost" + }, + "port": { + "enum": [ + "8082", + "80" + ], + "default": "8082" + } + } + } + ], + "security": [ + { + "basicAuth": [] + } + ], + "tags": [ + { + "name": "Server", + "description": "Server information" + }, + { + "name": "Session", + "description": "User session management" + }, + { + "name": "Devices", + "description": "Device management" + }, + { + "name": "Groups", + "description": "Group management" + }, + { + "name": "Users", + "description": "User management" + }, + { + "name": "Permissions", + "description": "User permissions and other object linking" + }, + { + "name": "Positions", + "description": "Retrieving raw location information" + }, + { + "name": "Events", + "description": "Retrieving event information" + }, + { + "name": "Reports", + "description": "Reports generation" + }, + { + "name": "Notifications", + "description": "User notifications management" + }, + { + "name": "Geofences", + "description": "Geofence management" + }, + { + "name": "Commands", + "description": "Sending commands to devices and stored command management" + }, + { + "name": "Attributes", + "description": "Computed attributes management" + }, + { + "name": "Drivers", + "description": "Drivers management" + }, + { + "name": "Maintenance", + "description": "Maintenance management" + }, + { + "name": "Calendars", + "description": "Calendar management" + }, + { + "name": "Statistics", + "description": "Retrieving server statistics" + } + ], + "paths": { + "/commands": { + "get": { + "summary": "Fetch a list of Saved Commands", + "tags": [ + "Commands" + ], + "description": "Without params, it returns a list of Saved Commands the user has access to", + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Command" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Saved Command", + "tags": [ + "Commands" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/commands/{id}": { + "put": { + "summary": "Update a Saved Command", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Saved Command", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/commands/send": { + "get": { + "summary": "Fetch a list of Saved Commands supported by Device at the moment", + "description": "Return a list of saved commands linked to Device and its groups, filtered by current Device protocol support", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Command" + } + } + } + } + }, + "400": { + "description": "Could happen when the user doesn't have permission for the device", + "content": {} + } + } + }, + "post": { + "summary": "Dispatch commands to device", + "description": "Dispatch a new command or Saved Command if _body.id_ set", + "tags": [ + "Commands" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Command sent", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + }, + "202": { + "description": "Command queued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + } + }, + "400": { + "description": "Could happen when the user doesn't have permission or an incorrect command _type_ for the device", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/commands/types": { + "get": { + "summary": "Fetch a list of available Commands for the Device or all possible Commands if Device ommited", + "tags": [ + "Commands" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "Internal device identifier. Only works if device has already reported some locations", + "schema": { + "type": "integer" + } + }, + { + "name": "protocol", + "in": "query", + "description": "Protocol name. Can be used instead of device id", + "schema": { + "type": "string" + } + }, + { + "name": "textChannel", + "in": "query", + "description": "When `true` return SMS commands. If not specified or `false` return data commands", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandType" + } + } + } + } + }, + "400": { + "description": "Could happen when trying to fetch from a device the user does not have permission", + "content": {} + } + } + } + }, + "/devices": { + "get": { + "summary": "Fetch a list of Devices", + "description": "Without any params, returns a list of the user's devices", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "id", + "in": "query", + "description": "To fetch one or more devices. Multiple params can be passed like `id=31&id=42`", + "schema": { + "type": "integer" + } + }, + { + "name": "uniqueId", + "in": "query", + "description": "To fetch one or more devices. Multiple params can be passed like `uniqueId=333331&uniqieId=44442`", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Device" + } + } + } + } + }, + "400": { + "description": "No permission", + "content": {} + } + } + }, + "post": { + "summary": "Create a Device", + "tags": [ + "Devices" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/devices/{id}": { + "put": { + "summary": "Update a Device", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Device", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/devices/{id}/accumulators": { + "put": { + "summary": "Update total distance and hours of the Device", + "tags": [ + "Devices" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceAccumulators" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No Content", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/groups": { + "get": { + "summary": "Fetch a list of Groups", + "description": "Without any params, returns a list of the Groups the user belongs to", + "tags": [ + "Groups" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Group" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Group", + "tags": [ + "Groups" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + } + }, + "400": { + "description": "No permission", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/groups/{id}": { + "put": { + "summary": "Update a Group", + "tags": [ + "Groups" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Group", + "tags": [ + "Groups" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/permissions": { + "post": { + "summary": "Link an Object to another Object", + "tags": [ + "Permissions" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Permission" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No Content", + "content": {} + }, + "400": { + "description": "No permission", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Unlink an Object from another Object", + "tags": [ + "Permissions" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Permission" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No Content", + "content": {} + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/positions": { + "get": { + "summary": "Fetches a list of Positions", + "description": "We strongly recommend using [Traccar WebSocket API](https://www.traccar.org/traccar-api/) instead of periodically polling positions endpoint. Without any params, it returns a list of last known positions for all the user's Devices. _from_ and _to_ fields are not required with _id_.", + "tags": [ + "Positions" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "_deviceId_ is optional, but requires the _from_ and _to_ parameters when used", + "schema": { + "type": "integer" + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "id", + "in": "query", + "description": "To fetch one or more positions. Multiple params can be passed like `id=31&id=42`", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + }, + "application/gpx+xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + } + } + } + } + } + }, + "/server": { + "get": { + "summary": "Fetch Server information", + "tags": [ + "Server" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Server" + } + } + } + } + } + }, + "put": { + "summary": "Update Server information", + "tags": [ + "Server" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Server" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Server" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/session": { + "get": { + "summary": "Fetch Session information", + "tags": [ + "Session" + ], + "parameters": [ + { + "name": "token", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "404": { + "description": "Not Found", + "content": {} + } + } + }, + "post": { + "summary": "Create a new Session", + "tags": [ + "Session" + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string", + "format": "password" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": {} + } + } + }, + "delete": { + "summary": "Close the Session", + "tags": [ + "Session" + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/session/openid/auth": { + "get": { + "summary": "Fetch Session information", + "tags": [ + "Session" + ], + "parameters": [ + { + } + ], + "responses": { + "303": { + "description": "Redirect to OpenID Connect identity provider", + "content": { } + } + } + } + }, + "/session/openid/callback": { + "get": { + "summary": "OpenID Callback", + "tags": [ + "Session" + ], + "parameters": [ + { + } + ], + "responses": { + "303": { + "description": "Successful authentication, redirect to homepage", + "content": { } + } + } + } + }, + "/users": { + "get": { + "summary": "Fetch a list of Users", + "tags": [ + "Users" + ], + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Can only be used by admin or manager users", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "400": { + "description": "No Permission", + "content": {} + } + } + }, + "post": { + "summary": "Create a User", + "tags": [ + "Users" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/users/{id}": { + "put": { + "summary": "Update a User", + "tags": [ + "Users" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a User", + "tags": [ + "Users" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/notifications": { + "get": { + "summary": "Fetch a list of Notifications", + "description": "Without params, it returns a list of Notifications the user has access to", + "tags": [ + "Notifications" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Notification" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Notification", + "tags": [ + "Notifications" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/notifications/{id}": { + "put": { + "summary": "Update a Notification", + "tags": [ + "Notifications" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Notification", + "tags": [ + "Notifications" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/notifications/types": { + "get": { + "summary": "Fetch a list of available Notification types", + "tags": [ + "Notifications" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationType" + } + } + } + } + } + } + } + }, + "/notifications/test": { + "post": { + "summary": "Send test notification to current user via Email and SMS", + "tags": [ + "Notifications" + ], + "responses": { + "204": { + "description": "Successful sending", + "content": {} + }, + "400": { + "description": "Could happen if sending has failed", + "content": {} + } + } + } + }, + "/geofences": { + "get": { + "summary": "Fetch a list of Geofences", + "description": "Without params, it returns a list of Geofences the user has access to", + "tags": [ + "Geofences" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Geofence" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Geofence", + "tags": [ + "Geofences" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/geofences/{id}": { + "put": { + "summary": "Update a Geofence", + "tags": [ + "Geofences" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Geofence", + "tags": [ + "Geofences" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/events/{id}": { + "get": { + "tags": [ + "Events" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event" + } + } + } + } + } + } + }, + "/reports/route": { + "get": { + "summary": "Fetch a list of Positions within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + } + } + } + } + } + }, + "/reports/events": { + "get": { + "summary": "Fetch a list of Events within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "type", + "in": "query", + "description": "% can be used to return events of all types", + "style": "form", + "explode": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Event" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Event" + } + } + } + } + } + } + } + }, + "/reports/summary": { + "get": { + "summary": "Fetch a list of ReportSummary within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportSummary" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportSummary" + } + } + } + } + } + } + } + }, + "/reports/trips": { + "get": { + "summary": "Fetch a list of ReportTrips within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportTrips" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportTrips" + } + } + } + } + } + } + } + }, + "/reports/stops": { + "get": { + "summary": "Fetch a list of ReportStops within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "tags": [ + "Reports" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportStops" + } + } + }, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportStops" + } + } + } + } + } + } + } + }, + "/statistics": { + "get": { + "summary": "Fetch server Statistics", + "tags": [ + "Statistics" + ], + "parameters": [ + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Statistics" + } + } + } + } + } + } + } + }, + "/calendars": { + "get": { + "summary": "Fetch a list of Calendars", + "description": "Without params, it returns a list of Calendars the user has access to", + "tags": [ + "Calendars" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Calendar" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Calendar", + "tags": [ + "Calendars" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/calendars/{id}": { + "put": { + "summary": "Update a Calendar", + "tags": [ + "Calendars" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Calendar", + "tags": [ + "Calendars" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/attributes/computed": { + "get": { + "summary": "Fetch a list of Attributes", + "description": "Without params, it returns a list of Attributes the user has access to", + "tags": [ + "Attributes" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Attribute" + } + } + } + } + } + } + }, + "post": { + "summary": "Create an Attribute", + "tags": [ + "Attributes" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/attributes/computed/{id}": { + "put": { + "summary": "Update an Attribute", + "tags": [ + "Attributes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete an Attribute", + "tags": [ + "Attributes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/drivers": { + "get": { + "summary": "Fetch a list of Drivers", + "description": "Without params, it returns a list of Drivers the user has access to", + "tags": [ + "Drivers" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Driver" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Driver", + "tags": [ + "Drivers" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/drivers/{id}": { + "put": { + "summary": "Update a Driver", + "tags": [ + "Drivers" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Driver", + "tags": [ + "Drivers" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + }, + "/maintenance": { + "get": { + "summary": "Fetch a list of Maintenance", + "description": "Without params, it returns a list of Maintenance the user has access to", + "tags": [ + "Maintenance" + ], + "parameters": [ + { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Maintenance" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a Maintenance", + "tags": [ + "Maintenance" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + } + }, + "/maintenance/{id}": { + "put": { + "summary": "Update a Maintenance", + "tags": [ + "Maintenance" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "delete": { + "summary": "Delete a Maintenance", + "tags": [ + "Maintenance" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + } + } + } + } + }, + "components": { + "schemas": { + "Position": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "deviceId": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "deviceTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "fixTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "serverTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "outdated": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "altitude": { + "type": "number" + }, + "speed": { + "type": "number", + "description": "in knots" + }, + "course": { + "type": "number" + }, + "address": { + "type": "string" + }, + "accuracy": { + "type": "number" + }, + "network": { + "type": "object", + "properties": {} + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "readonly": { + "type": "boolean" + }, + "administrator": { + "type": "boolean" + }, + "map": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "zoom": { + "type": "integer" + }, + "password": { + "type": "string" + }, + "twelveHourFormat": { + "type": "boolean" + }, + "coordinateFormat": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "expirationTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "deviceLimit": { + "type": "integer" + }, + "userLimit": { + "type": "integer" + }, + "deviceReadonly": { + "type": "boolean" + }, + "limitCommands": { + "type": "boolean" + }, + "poiLayer": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Server": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "registration": { + "type": "boolean" + }, + "readonly": { + "type": "boolean" + }, + "deviceReadonly": { + "type": "boolean" + }, + "limitCommands": { + "type": "boolean" + }, + "map": { + "type": "string" + }, + "bingKey": { + "type": "string" + }, + "mapUrl": { + "type": "string" + }, + "poiLayer": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "zoom": { + "type": "integer" + }, + "twelveHourFormat": { + "type": "boolean" + }, + "version": { + "type": "string" + }, + "forceSettings": { + "type": "boolean" + }, + "coordinateFormat": { + "type": "string" + }, + "openIdEnabled": { + "type": "boolean" + }, + "openIdForce": { + "type": "boolean" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Command": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "deviceId": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Device": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "uniqueId": { + "type": "string" + }, + "status": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "lastUpdate": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "positionId": { + "type": "integer" + }, + "groupId": { + "type": "integer" + }, + "phone": { + "type": "string" + }, + "model": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "category": { + "type": "string" + }, + "geofenceIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Group": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Permission": { + "type": "object", + "properties": { + "userId": { + "type": "integer", + "description": "User Id, can be only first parameter" + }, + "deviceId": { + "type": "integer", + "description": "Device Id, can be first parameter or second only in combination with userId" + }, + "groupId": { + "type": "integer", + "description": "Group Id, can be first parameter or second only in combination with userId" + }, + "geofenceId": { + "type": "integer", + "description": "Geofence Id, can be second parameter only" + }, + "notificationId": { + "type": "integer", + "description": "Notification Id, can be second parameter only" + }, + "calendarId": { + "type": "integer", + "description": "Calendar Id, can be second parameter only and only in combination with userId" + }, + "attributeId": { + "type": "integer", + "description": "Computed Attribute Id, can be second parameter only" + }, + "driverId": { + "type": "integer", + "description": "Driver Id, can be second parameter only" + }, + "managedUserId": { + "type": "integer", + "description": "User Id, can be second parameter only and only in combination with userId" + } + }, + "description": "This is a permission map that contain two object indexes. It is used to link/unlink objects. Order is important. Example: { deviceId:8, geofenceId: 16 }" + }, + "CommandType": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + }, + "Geofence": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "area": { + "type": "string" + }, + "calendarId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Notification": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "always": { + "type": "boolean" + }, + "web": { + "type": "boolean" + }, + "mail": { + "type": "boolean" + }, + "sms": { + "type": "boolean" + }, + "calendarId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "NotificationType": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + }, + "Event": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "eventTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "deviceId": { + "type": "integer" + }, + "positionId": { + "type": "integer" + }, + "geofenceId": { + "type": "integer" + }, + "maintenanceId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "ReportSummary": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "maxSpeed": { + "type": "number", + "description": "in knots" + }, + "averageSpeed": { + "type": "number", + "description": "in knots" + }, + "distance": { + "type": "number", + "description": "in meters" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "engineHours": { + "type": "integer" + } + } + }, + "ReportTrips": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "maxSpeed": { + "type": "number", + "description": "in knots" + }, + "averageSpeed": { + "type": "number", + "description": "in knots" + }, + "distance": { + "type": "number", + "description": "in meters" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "duration": { + "type": "integer" + }, + "startTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "startAddress": { + "type": "string" + }, + "startLat": { + "type": "number" + }, + "startLon": { + "type": "number" + }, + "endTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "endAddress": { + "type": "string" + }, + "endLat": { + "type": "number" + }, + "endLon": { + "type": "number" + }, + "driverUniqueId": { + "type": "integer" + }, + "driverName": { + "type": "string" + } + } + }, + "ReportStops": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "duration": { + "type": "integer" + }, + "startTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "address": { + "type": "string" + }, + "lat": { + "type": "number" + }, + "lon": { + "type": "number" + }, + "endTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "engineHours": { + "type": "integer" + } + } + }, + "Statistics": { + "type": "object", + "properties": { + "captureTime": { + "type": "string", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "format": "date-time" + }, + "activeUsers": { + "type": "integer" + }, + "activeDevices": { + "type": "integer" + }, + "requests": { + "type": "integer" + }, + "messagesReceived": { + "type": "integer" + }, + "messagesStored": { + "type": "integer" + } + } + }, + "DeviceAccumulators": { + "type": "object", + "properties": { + "deviceId": { + "type": "integer" + }, + "totalDistance": { + "type": "number", + "description": "in meters" + }, + "hours": { + "type": "number" + } + } + }, + "Calendar": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "data": { + "type": "string", + "description": "base64 encoded in iCalendar format" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Attribute": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "attribute": { + "type": "string" + }, + "expression": { + "type": "string" + }, + "type": { + "type": "string", + "description": "String|Number|Boolean" + } + } + }, + "Driver": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "uniqueId": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + }, + "Maintenance": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "start": { + "type": "number" + }, + "period": { + "type": "number" + }, + "attributes": { + "type": "object", + "properties": {} + } + } + } + }, + "parameters": { + "entityId": { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + "all": { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "schema": { + "type": "boolean" + } + }, + "refresh": { + "name": "refresh", + "in": "query", + "schema": { + "type": "boolean" + } + }, + "userId": { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "schema": { + "type": "integer" + } + }, + "deviceId": { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "schema": { + "type": "integer" + } + }, + "groupId": { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "schema": { + "type": "integer" + } + }, + "deviceIdArray": { + "name": "deviceId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "groupIdArray": { + "name": "groupId", + "in": "query", + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "fromTime": { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + "toTime": { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + } + }, + "requestBodies": { + "Device": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Device" + } + } + }, + "required": true + }, + "Permission": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Permission" + } + } + }, + "required": true + }, + "Group": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Group" + } + } + }, + "required": true + }, + "User": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "Geofence": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Geofence" + } + } + }, + "required": true + }, + "Calendar": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Calendar" + } + } + }, + "required": true + }, + "Attribute": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Attribute" + } + } + }, + "required": true + }, + "Driver": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Driver" + } + } + }, + "required": true + }, + "Command": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Command" + } + } + }, + "required": true + }, + "Notification": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + }, + "required": true + }, + "Maintenance": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Maintenance" + } + } + }, + "required": true + } + }, + "securitySchemes": { + "basicAuth": { + "type": "http", + "description": "Basic HTTP authorization with _email_ and _password_", + "scheme": "basic" + } + } + } +} -- cgit v1.2.3 From 9de791026d5aaf5b5997ed7fab4d30c6cb1fb057 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 17:53:15 +0100 Subject: Lint fixes --- src/main/java/org/traccar/MainModule.java | 2 +- .../org/traccar/api/resource/ServerResource.java | 2 +- .../org/traccar/api/resource/SessionResource.java | 2 +- .../org/traccar/api/resource/UserResource.java | 1 - .../org/traccar/api/security/LoginService.java | 2 +- src/main/java/org/traccar/config/Keys.java | 2 +- .../java/org/traccar/database/OpenIdProvider.java | 73 ++++++++++++---------- 7 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 7b06b4840..51097511a 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -171,7 +171,7 @@ public class MainModule extends AbstractModule { } return null; } - + @Singleton @Provides public static OpenIdProvider provideOpenIDProvider(Config config, LoginService loginService) { diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 9b4d82a66..6a3b8919e 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -71,7 +71,7 @@ public class ServerResource extends BaseResource { server.setEmailEnabled(mailManager.getEmailEnabled()); server.setGeocoderEnabled(geocoder != null); server.setOpenIdEnabled(openIdProvider != null); - server.setOpenIdForce(openIdProvider != null && openIdProvider.force); + server.setOpenIdForce(openIdProvider != null && openIdProvider.getForce()); User user = permissionsService.getUser(getUserId()); if (user != null) { if (user.getAdministrator()) { diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 94a6a4595..ac39fa449 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -174,7 +174,7 @@ public class SessionResource extends BaseResource { public Response openIdAuth() throws IOException { return Response.seeOther(openIdProvider.createAuthUri()).build(); } - + @PermitAll @Path("openid/callback") @GET diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 1c58cec3c..19d88782f 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -17,7 +17,6 @@ package org.traccar.api.resource; import org.traccar.api.BaseObjectResource; import org.traccar.config.Config; -import org.traccar.config.Keys; import org.traccar.helper.LogAction; import org.traccar.helper.model.UserUtil; import org.traccar.model.ManagedUser; diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index d92f7ce15..c7482a2e3 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -107,7 +107,7 @@ public class LoginService { user.setEmail(email); user.setFixedEmail(true); user.setAdministrator(administrator); - user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); checkUserEnabled(user); return user; } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index a666667d4..707e9e815 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -628,7 +628,7 @@ public final class Keys { List.of(KeyType.CONFIG)); /** - * OpenID Connect Client Secret. + * OpenID Connect Client Secret. * This is a secret assigned to each application you register with your identity provider. * Required to enable SSO. */ diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 5e5c54523..f5c7eef15 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -50,7 +50,6 @@ import com.nimbusds.oauth2.sdk.token.BearerAccessToken; import com.nimbusds.oauth2.sdk.id.State; import com.nimbusds.oauth2.sdk.id.ClientID; import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; -import com.nimbusds.openid.connect.sdk.Nonce; import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; import com.nimbusds.openid.connect.sdk.UserInfoResponse; import com.nimbusds.openid.connect.sdk.UserInfoRequest; @@ -60,8 +59,8 @@ import com.nimbusds.openid.connect.sdk.claims.UserInfo; public class OpenIdProvider { private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdProvider.class); - - public final Boolean force; + + private final Boolean force; private final ClientID clientId; private final ClientAuthentication clientAuth; private URI callbackUrl; @@ -74,7 +73,7 @@ public class OpenIdProvider { private LoginService loginService; @Inject - public OpenIdProvider(Config config, LoginService loginService) { + public OpenIdProvider(Config config, LoginService loginService) { this.loginService = loginService; force = config.getBoolean(Keys.OPENID_FORCE); @@ -87,7 +86,7 @@ public class OpenIdProvider { tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - } catch(URISyntaxException error) { + } catch (URISyntaxException error) { LOGGER.error("Invalid URIs provided in OpenID configuration"); } @@ -100,24 +99,25 @@ public class OpenIdProvider { new Scope("openid", "profile", "email", "groups"), clientId, callbackUrl); - + return request.endpointURI(authUrl) .state(new State()) .build() .toURI(); } - private OIDCTokenResponse getToken(AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { - AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); - TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); + private OIDCTokenResponse getToken( + AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { + AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); + TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); - HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send(); - TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse); - if (!token.indicatesSuccess()) { - throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); - } + HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send(); + TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse); + if (!token.indicatesSuccess()) { + throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); + } - return (OIDCTokenResponse) token.toSuccessResponse(); + return (OIDCTokenResponse) token.toSuccessResponse(); } private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException { @@ -128,36 +128,45 @@ public class OpenIdProvider { UserInfoResponse userInfoResponse = UserInfoResponse.parse(httpResponse); if (!userInfoResponse.indicatesSuccess()) { - throw new GeneralSecurityException("Failed to access OpenID Connect user info endpoint. Please contact your administrator."); + throw new GeneralSecurityException( + "Failed to access OpenID Connect user info endpoint. Please contact your administrator."); } return userInfoResponse.toSuccessResponse().getUserInfo(); } - public URI handleCallback(URI requestUri, HttpServletRequest request) throws StorageException, ParseException, IOException, GeneralSecurityException { - AuthorizationResponse response = AuthorizationResponse.parse(requestUri); + public URI handleCallback( + URI requestUri, HttpServletRequest request + ) throws StorageException, ParseException, IOException, GeneralSecurityException { + AuthorizationResponse response = AuthorizationResponse.parse(requestUri); - if (!response.indicatesSuccess()) { - throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); - } + if (!response.indicatesSuccess()) { + throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); + } - AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); + AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); - if (authCode == null) { - throw new GeneralSecurityException( "Malformed OpenID callback."); - } + if (authCode == null) { + throw new GeneralSecurityException("Malformed OpenID callback."); + } + + OIDCTokenResponse tokens = getToken(authCode); - OIDCTokenResponse tokens = getToken(authCode); + BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); - BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); + UserInfo userInfo = getUserInfo(bearerToken); - UserInfo userInfo = getUserInfo(bearerToken); + User user = loginService.login( + userInfo.getEmailAddress(), userInfo.getName(), + userInfo.getStringListClaim("groups").contains(adminGroup)); - User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), userInfo.getStringListClaim("groups").contains(adminGroup)); + request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); - request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return baseUrl; + } - return baseUrl; + public boolean getForce() { + return force; } } -- cgit v1.2.3 From 7c4d232d4689ce4ea5fb2db9ad5d2cfb18ad3806 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 17:54:49 +0100 Subject: Revert submodule changes --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 87e9c7dd5..506dd66b7 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 87e9c7dd5159c1d08368bfafa30fed9ae811933c +Subproject commit 506dd66b793803a24a2872e242482f263087df52 -- cgit v1.2.3 From d05049c4fcad15b014d4d7178f3b88de7c0c7a28 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 18:09:22 +0100 Subject: Reverting - try again --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 506dd66b7..091d10531 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 506dd66b793803a24a2872e242482f263087df52 +Subproject commit 091d10531a59216c5f0a812609742e097c68ff2c -- cgit v1.2.3 From a16da3bef30b26cbf813526dee817538b99d9d6e Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 21:30:28 +0100 Subject: Support providers who do not provide the groups scope --- src/main/java/org/traccar/config/Keys.java | 6 +++--- src/main/java/org/traccar/database/OpenIdProvider.java | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 707e9e815..3ff423ad1 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -665,12 +665,12 @@ public final class Keys { /** * OpenID Connect group to grant admin access. - * Defaults to admins. + * If this is not provided, no groups will be granted admin access. + * This option will only work if your OpenID provider supports the groups scope. */ public static final ConfigKey OPENID_ADMINGROUP = new StringConfigKey( "openid.adminGroup", - List.of(KeyType.CONFIG), - "admins"); + List.of(KeyType.CONFIG)); /** * If no data is reported by a device for the given amount of time, status changes from online to unknown. Value is diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index f5c7eef15..537319b31 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -94,9 +94,15 @@ public class OpenIdProvider { } public URI createAuthUri() { + Scope scope = new Scope("openid", "profile", "email"); + + if (adminGroup != null) { + scope.add("groups"); + } + AuthenticationRequest.Builder request = new AuthenticationRequest.Builder( new ResponseType("code"), - new Scope("openid", "profile", "email", "groups"), + scope, clientId, callbackUrl); @@ -156,9 +162,9 @@ public class OpenIdProvider { UserInfo userInfo = getUserInfo(bearerToken); - User user = loginService.login( - userInfo.getEmailAddress(), userInfo.getName(), - userInfo.getStringListClaim("groups").contains(adminGroup)); + Boolean administrator = adminGroup != null && userInfo.getStringListClaim("groups").contains(adminGroup); + + User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), administrator); request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); -- cgit v1.2.3 From cf992ec194ef8fbcd86ad170bdc68c6075712591 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 3 Apr 2023 22:22:20 +0100 Subject: Block login when openid is forced --- src/main/java/org/traccar/api/security/LoginService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index c7482a2e3..db9ed6cff 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -43,6 +43,7 @@ public class LoginService { private final String serviceAccountToken; private final boolean forceLdap; + private final boolean forceOpenId; @Inject public LoginService( @@ -53,6 +54,7 @@ public class LoginService { this.ldapProvider = ldapProvider; serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN); forceLdap = config.getBoolean(Keys.LDAP_FORCE); + forceOpenId = config.getBoolean(Keys.OPENID_FORCE); } public User login(String token) throws StorageException, GeneralSecurityException, IOException { @@ -69,6 +71,10 @@ public class LoginService { } public User login(String email, String password) throws StorageException { + if (forceOpenId) { + return null; + } + email = email.trim(); User user = storage.getObject(User.class, new Request( new Columns.All(), -- cgit v1.2.3 From 77e98161d8742548ef4082054304bad21f7324ac Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 4 Apr 2023 11:02:05 -0700 Subject: Handle FMB920 LTE cell info --- .../traccar/protocol/TeltonikaProtocolDecoder.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 929eca8aa..ead657893 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -253,7 +253,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(182, null, (p, b) -> p.set(Position.KEY_HDOP, b.readUnsignedShort() * 0.1)); register(199, null, (p, b) -> p.set(Position.KEY_ODOMETER_TRIP, b.readUnsignedInt())); register(200, fmbXXX, (p, b) -> p.set("sleepMode", b.readUnsignedByte())); - register(205, fmbXXX, (p, b) -> p.set("cid", b.readUnsignedShort())); + register(205, fmbXXX, (p, b) -> p.set("cid2g", b.readUnsignedShort())); register(206, fmbXXX, (p, b) -> p.set("lac", b.readUnsignedShort())); register(236, null, (p, b) -> { p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null); @@ -276,6 +276,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { break; } }); + register(636, fmbXXX, (p, b) -> p.set("cid4g", b.readUnsignedInt())); } private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) { @@ -366,10 +367,18 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(network); } } else { - Integer cid = (Integer) position.getAttributes().remove("cid"); + Integer cid2g = (Integer) position.getAttributes().remove("cid2g"); + Long cid4g = (Long) position.getAttributes().remove("cid4g"); Integer lac = (Integer) position.getAttributes().remove("lac"); - if (cid != null && lac != null) { - CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid); + if (lac != null && (cid2g != null || cid4g != null)) { + CellTower cellTower; + if (cid2g != null) { + cellTower = CellTower.fromLacCid(getConfig(), lac, cid2g); + cellTower.setRadioType("gsm"); + } else { + cellTower = CellTower.fromLacCid(getConfig(), lac, cid4g); + cellTower.setRadioType("lte"); + } long operator = position.getInteger(Position.KEY_OPERATOR); if (operator >= 1000) { cellTower.setOperator(operator); -- cgit v1.2.3 From 9423dad9bc56674dd864897c9c0265ca8cea6670 Mon Sep 17 00:00:00 2001 From: Roberto Murguia Date: Tue, 4 Apr 2023 17:14:29 -0500 Subject: Add DELETE api endpoint for Positions --- .../org/traccar/api/resource/PositionResource.java | 17 ++++++++ swagger.json | 48 ++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 042dd1e23..37696a620 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -31,6 +31,7 @@ import org.traccar.storage.query.Request; import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.DELETE; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; @@ -43,6 +44,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.LinkedList; @Path("positions") @Produces(MediaType.APPLICATION_JSON) @@ -86,6 +88,21 @@ public class PositionResource extends BaseResource { } } + @DELETE + public Response remove( + @QueryParam("deviceId") long deviceId, + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { + permissionsService.checkPermission(Device.class, getUserId(), deviceId); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly); + + var conditions = new LinkedList(); + conditions.add(new Condition.Equals("deviceId", deviceId)); + conditions.add(new Condition.Between("fixTime", "from", from, "to", to)); + storage.removeObject(Position.class, new Request(Condition.merge(conditions))); + + return Response.status(Response.Status.NO_CONTENT).build(); + } + @Path("kml") @GET @Produces("application/vnd.google-earth.kml+xml") diff --git a/swagger.json b/swagger.json index 6c1e21d28..467925ca9 100644 --- a/swagger.json +++ b/swagger.json @@ -873,6 +873,54 @@ } } } + }, + "delete": { + "summary": "Deletes all the Positions of a device in the time span specified", + "description": "", + "tags": [ + "Positions" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "", + "schema": { + "type": "integer" + }, + "required": true + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": true + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": true + } + ], + "responses": { + "204": { + "description": "No Content", + "content": {} + }, + "400": { + "description": "Bad Request", + "content": {} + } + } } }, "/server": { -- cgit v1.2.3 From 1efa87637b05709b35554ae262d2373d37d36a7b Mon Sep 17 00:00:00 2001 From: brzsmg Date: Wed, 5 Apr 2023 19:12:52 +0300 Subject: Update CONTRIBUTING.md spelling --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 03a3831b9..ba524068f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -36,7 +36,7 @@ Provide as much details as possible, including log fragments, operating system a Before creating a feature request make sure that the feature or modification that you are requesting is not yet implemented. -Search reposiroty to ensure that there is no existing issues for your request. If there is, add a new comment on that issue. +Search repository to ensure that there is no existing issues for your request. If there is, add a new comment on that issue. Provide as much details as possible, including use case for your feature and any benefits that you can think of. -- cgit v1.2.3 From 9ab4a6e303c0e8a4997252b4c6a8b2dd601d73af Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 5 Apr 2023 17:40:11 +0100 Subject: Implement OpenID auto discovery --- src/main/java/org/traccar/config/Keys.java | 15 ++++++-- .../java/org/traccar/database/OpenIdProvider.java | 44 ++++++++++++++++++++-- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 3ff423ad1..3ed6c6026 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -636,11 +636,20 @@ public final class Keys { "openid.clientSecret", List.of(KeyType.CONFIG)); + /** + * OpenID Connect Issuer (Base) URL. + * This is used to automatically configure the authorization, token and user info URLs if + * they are not provided. + */ + public static final ConfigKey OPENID_ISSUERURL = new StringConfigKey( + "openid.issuerUrl", + List.of(KeyType.CONFIG)); + /** * OpenID Connect Authorization URL. * This can usually be found in the documentation of your identity provider or by using the well-known * configuration endpoint, eg. https://auth.example.com//.well-known/openid-configuration - * Required to enable SSO. + * Required to enable SSO if openid.issuerUrl is not set. */ public static final ConfigKey OPENID_AUTHURL = new StringConfigKey( "openid.authUrl", @@ -648,7 +657,7 @@ public final class Keys { /** * OpenID Connect Token URL. * This can be found in the same ways at openid.authUrl. - * Required to enable SSO. + * Required to enable SSO if openid.issuerUrl is not set. */ public static final ConfigKey OPENID_TOKENURL = new StringConfigKey( "openid.tokenUrl", @@ -657,7 +666,7 @@ public final class Keys { /** * OpenID Connect User Info URL. * This can be found in the same ways at openid.authUrl. - * Required to enable SSO. + * Required to enable SSO if openid.issuerUrl is not set. */ public static final ConfigKey OPENID_USERINFOURL = new StringConfigKey( "openid.userInfoUrl", diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 537319b31..2b0f9d290 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -26,9 +26,16 @@ import org.traccar.helper.ServletHelper; import java.net.URI; import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse.BodyHandlers; import java.security.GeneralSecurityException; +import java.util.Map; import java.io.IOException; import javax.servlet.http.HttpServletRequest; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,12 +89,43 @@ public class OpenIdProvider { try { callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); - authUrl = new URI(config.getString(Keys.OPENID_AUTHURL, "")); - tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL, "")); - userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL, "")); baseUrl = new URI(config.getString(Keys.WEB_URL, "")); + + if ( + config.hasKey(Keys.OPENID_ISSUERURL) + && ( + !config.hasKey(Keys.OPENID_AUTHURL) + || !config.hasKey(Keys.OPENID_TOKENURL) + || !config.hasKey(Keys.OPENID_USERINFOURL)) + ) { + HttpClient httpClient = HttpClient.newHttpClient(); + + HttpRequest httpRequest = HttpRequest.newBuilder( + URI.create( + config.getString(Keys.OPENID_ISSUERURL) + "/.well-known/openid-configuration") + ) + .header("accept", "application/json") + .build(); + + String httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); + + Map discoveryMap = new ObjectMapper().readValue( + httpResponse, new TypeReference>() { }); + + authUrl = new URI(discoveryMap.get("authorization_endpoint").toString()); + tokenUrl = new URI(discoveryMap.get("token_endpoint").toString()); + userInfoUrl = new URI(discoveryMap.get("userinfo_endpoint").toString()); + + LOGGER.info("OpenID Connect auto discovery successful"); + } else { + authUrl = new URI(config.getString(Keys.OPENID_AUTHURL)); + tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL)); + userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL)); + } } catch (URISyntaxException error) { LOGGER.error("Invalid URIs provided in OpenID configuration"); + } catch (InterruptedException | IOException error) { + LOGGER.error("OpenID Connect auto discovery failed"); } adminGroup = config.getString(Keys.OPENID_ADMINGROUP); -- cgit v1.2.3 From c56b136a328bc1781ccc74aa27fdecf4a17b9595 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 5 Apr 2023 17:59:04 +0100 Subject: Added openid.allowGroup --- src/main/java/org/traccar/config/Keys.java | 9 +++++++++ src/main/java/org/traccar/database/OpenIdProvider.java | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 3ed6c6026..363d4a472 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -672,6 +672,15 @@ public final class Keys { "openid.userInfoUrl", List.of(KeyType.CONFIG)); + /** + * OpenID Connect group to restrict access to. + * If this is not provided, all OpenID users will have access to Traccar. + * This option will only work if your OpenID provider supports the groups scope. + */ + public static final ConfigKey OPENID_ALLOWGROUP = new StringConfigKey( + "openid.allowGroup", + List.of(KeyType.CONFIG)); + /** * OpenID Connect group to grant admin access. * If this is not provided, no groups will be granted admin access. diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 2b0f9d290..370876ed9 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -30,6 +30,7 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse.BodyHandlers; import java.security.GeneralSecurityException; +import java.util.List; import java.util.Map; import java.io.IOException; import javax.servlet.http.HttpServletRequest; @@ -76,6 +77,7 @@ public class OpenIdProvider { private URI userInfoUrl; private URI baseUrl; private final String adminGroup; + private final String allowGroup; private LoginService loginService; @@ -129,6 +131,7 @@ public class OpenIdProvider { } adminGroup = config.getString(Keys.OPENID_ADMINGROUP); + allowGroup = config.getString(Keys.OPENID_ALLOWGROUP); } public URI createAuthUri() { @@ -200,7 +203,12 @@ public class OpenIdProvider { UserInfo userInfo = getUserInfo(bearerToken); - Boolean administrator = adminGroup != null && userInfo.getStringListClaim("groups").contains(adminGroup); + List userGroups = userInfo.getStringListClaim("groups"); + Boolean administrator = adminGroup != null && userGroups.contains(adminGroup); + + if (!(administrator || allowGroup == null || userGroups.contains(allowGroup))) { + throw new GeneralSecurityException("Your OpenID Groups do not permit access to Traccar."); + } User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), administrator); -- cgit v1.2.3 From 5ba5cc8291d0bd5d497563ddebf08dfc6d239ee9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 5 Apr 2023 20:40:09 +0100 Subject: Review changes --- src/main/java/org/traccar/MainModule.java | 12 +++-- src/main/java/org/traccar/config/Keys.java | 16 +++--- .../java/org/traccar/database/OpenIdProvider.java | 62 +++++++++------------- 3 files changed, 41 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 51097511a..220798767 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -97,6 +97,7 @@ import javax.ws.rs.client.ClientBuilder; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; +import java.net.http.HttpClient; import java.util.Properties; public class MainModule extends AbstractModule { @@ -174,11 +175,12 @@ public class MainModule extends AbstractModule { @Singleton @Provides - public static OpenIdProvider provideOpenIDProvider(Config config, LoginService loginService) { - if (config.hasKey(Keys.OPENID_CLIENTID)) { - return new OpenIdProvider(config, loginService); - } - return null; + public static OpenIdProvider provideOpenIDProvider( + Config config, LoginService loginService, ObjectMapper objectMapper) throws InterruptedException, IOException { + if (config.hasKey(Keys.OPENID_CLIENT_ID)) { + return new OpenIdProvider(config, loginService, HttpClient.newHttpClient(), objectMapper); + } + return null; } @Provides diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 363d4a472..6c46ef390 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -623,7 +623,7 @@ public final class Keys { * This is a unique ID assigned to each application you register with your identity provider. * Required to enable SSO. */ - public static final ConfigKey OPENID_CLIENTID = new StringConfigKey( + public static final ConfigKey OPENID_CLIENT_ID = new StringConfigKey( "openid.clientId", List.of(KeyType.CONFIG)); @@ -632,7 +632,7 @@ public final class Keys { * This is a secret assigned to each application you register with your identity provider. * Required to enable SSO. */ - public static final ConfigKey OPENID_CLIENTSECRET = new StringConfigKey( + public static final ConfigKey OPENID_CLIENT_SECRET = new StringConfigKey( "openid.clientSecret", List.of(KeyType.CONFIG)); @@ -641,7 +641,7 @@ public final class Keys { * This is used to automatically configure the authorization, token and user info URLs if * they are not provided. */ - public static final ConfigKey OPENID_ISSUERURL = new StringConfigKey( + public static final ConfigKey OPENID_ISSUER_URL = new StringConfigKey( "openid.issuerUrl", List.of(KeyType.CONFIG)); @@ -651,7 +651,7 @@ public final class Keys { * configuration endpoint, eg. https://auth.example.com//.well-known/openid-configuration * Required to enable SSO if openid.issuerUrl is not set. */ - public static final ConfigKey OPENID_AUTHURL = new StringConfigKey( + public static final ConfigKey OPENID_AUTH_URL = new StringConfigKey( "openid.authUrl", List.of(KeyType.CONFIG)); /** @@ -659,7 +659,7 @@ public final class Keys { * This can be found in the same ways at openid.authUrl. * Required to enable SSO if openid.issuerUrl is not set. */ - public static final ConfigKey OPENID_TOKENURL = new StringConfigKey( + public static final ConfigKey OPENID_TOKEN_URL = new StringConfigKey( "openid.tokenUrl", List.of(KeyType.CONFIG)); @@ -668,7 +668,7 @@ public final class Keys { * This can be found in the same ways at openid.authUrl. * Required to enable SSO if openid.issuerUrl is not set. */ - public static final ConfigKey OPENID_USERINFOURL = new StringConfigKey( + public static final ConfigKey OPENID_USERINFO_URL = new StringConfigKey( "openid.userInfoUrl", List.of(KeyType.CONFIG)); @@ -677,7 +677,7 @@ public final class Keys { * If this is not provided, all OpenID users will have access to Traccar. * This option will only work if your OpenID provider supports the groups scope. */ - public static final ConfigKey OPENID_ALLOWGROUP = new StringConfigKey( + public static final ConfigKey OPENID_ALLOW_GROUP = new StringConfigKey( "openid.allowGroup", List.of(KeyType.CONFIG)); @@ -686,7 +686,7 @@ public final class Keys { * If this is not provided, no groups will be granted admin access. * This option will only work if your OpenID provider supports the groups scope. */ - public static final ConfigKey OPENID_ADMINGROUP = new StringConfigKey( + public static final ConfigKey OPENID_ADMIN_GROUP = new StringConfigKey( "openid.adminGroup", List.of(KeyType.CONFIG)); diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 370876ed9..8b93feea7 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -82,56 +82,46 @@ public class OpenIdProvider { private LoginService loginService; @Inject - public OpenIdProvider(Config config, LoginService loginService) { - this.loginService = loginService; - - force = config.getBoolean(Keys.OPENID_FORCE); - clientId = new ClientID(config.getString(Keys.OPENID_CLIENTID)); - clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENTSECRET))); - - try { - callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); - baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - - if ( - config.hasKey(Keys.OPENID_ISSUERURL) - && ( - !config.hasKey(Keys.OPENID_AUTHURL) - || !config.hasKey(Keys.OPENID_TOKENURL) - || !config.hasKey(Keys.OPENID_USERINFOURL)) - ) { - HttpClient httpClient = HttpClient.newHttpClient(); + public OpenIdProvider( + Config config, LoginService loginService, HttpClient httpClient, ObjectMapper objectMapper + ) throws InterruptedException, IOException { + this.loginService = loginService; + force = config.getBoolean(Keys.OPENID_FORCE); + clientId = new ClientID(config.getString(Keys.OPENID_CLIENT_ID)); + clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENT_SECRET))); + + try { + callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); + baseUrl = new URI(config.getString(Keys.WEB_URL, "")); + + if (config.hasKey(Keys.OPENID_ISSUER_URL)) { HttpRequest httpRequest = HttpRequest.newBuilder( - URI.create( - config.getString(Keys.OPENID_ISSUERURL) + "/.well-known/openid-configuration") - ) - .header("accept", "application/json") + URI.create(config.getString(Keys.OPENID_ISSUER_URL) + "/.well-known/openid-configuration")) + .header("Accept", "application/json") .build(); String httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); - Map discoveryMap = new ObjectMapper().readValue( + Map discoveryMap = objectMapper.readValue( httpResponse, new TypeReference>() { }); - authUrl = new URI(discoveryMap.get("authorization_endpoint").toString()); - tokenUrl = new URI(discoveryMap.get("token_endpoint").toString()); - userInfoUrl = new URI(discoveryMap.get("userinfo_endpoint").toString()); + authUrl = new URI((String) discoveryMap.get("authorization_endpoint")); + tokenUrl = new URI((String) discoveryMap.get("token_endpoint")); + userInfoUrl = new URI((String) discoveryMap.get("userinfo_endpoint")); LOGGER.info("OpenID Connect auto discovery successful"); - } else { - authUrl = new URI(config.getString(Keys.OPENID_AUTHURL)); - tokenUrl = new URI(config.getString(Keys.OPENID_TOKENURL)); - userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFOURL)); - } + } else { + authUrl = new URI(config.getString(Keys.OPENID_AUTH_URL)); + tokenUrl = new URI(config.getString(Keys.OPENID_TOKEN_URL)); + userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFO_URL)); + } } catch (URISyntaxException error) { LOGGER.error("Invalid URIs provided in OpenID configuration"); - } catch (InterruptedException | IOException error) { - LOGGER.error("OpenID Connect auto discovery failed"); } - adminGroup = config.getString(Keys.OPENID_ADMINGROUP); - allowGroup = config.getString(Keys.OPENID_ALLOWGROUP); + adminGroup = config.getString(Keys.OPENID_ADMIN_GROUP); + allowGroup = config.getString(Keys.OPENID_ALLOW_GROUP); } public URI createAuthUri() { -- cgit v1.2.3 From 1ecd7efca41344f29f8caa42fc6caaed8c7294a1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 5 Apr 2023 20:49:10 +0100 Subject: Config doc change --- src/main/java/org/traccar/config/Keys.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6c46ef390..b97acfd66 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -638,8 +638,7 @@ public final class Keys { /** * OpenID Connect Issuer (Base) URL. - * This is used to automatically configure the authorization, token and user info URLs if - * they are not provided. + * This is used to automatically configure the authorization, token and user info URLs if provided. */ public static final ConfigKey OPENID_ISSUER_URL = new StringConfigKey( "openid.issuerUrl", -- cgit v1.2.3 From a710ddd5ad336cd45d3a0e69f13985db840763dc Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 5 Apr 2023 21:45:37 +0100 Subject: Review changes 2 --- src/main/java/org/traccar/MainModule.java | 12 ++-- .../java/org/traccar/database/OpenIdProvider.java | 67 +++++++++------------- 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 220798767..4db6e0e32 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -96,6 +96,7 @@ import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import java.io.IOException; import java.net.InetAddress; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.net.http.HttpClient; import java.util.Properties; @@ -176,11 +177,12 @@ public class MainModule extends AbstractModule { @Singleton @Provides public static OpenIdProvider provideOpenIDProvider( - Config config, LoginService loginService, ObjectMapper objectMapper) throws InterruptedException, IOException { - if (config.hasKey(Keys.OPENID_CLIENT_ID)) { - return new OpenIdProvider(config, loginService, HttpClient.newHttpClient(), objectMapper); - } - return null; + Config config, LoginService loginService, ObjectMapper objectMapper + ) throws InterruptedException, IOException, URISyntaxException { + if (config.hasKey(Keys.OPENID_CLIENT_ID)) { + return new OpenIdProvider(config, loginService, HttpClient.newHttpClient(), objectMapper); + } + return null; } @Provides diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 8b93feea7..941d0e587 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -38,8 +38,6 @@ import javax.servlet.http.HttpServletRequest; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.AuthorizationCode; @@ -62,12 +60,9 @@ import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; import com.nimbusds.openid.connect.sdk.UserInfoResponse; import com.nimbusds.openid.connect.sdk.UserInfoRequest; import com.nimbusds.openid.connect.sdk.AuthenticationRequest; - import com.nimbusds.openid.connect.sdk.claims.UserInfo; public class OpenIdProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdProvider.class); - private final Boolean force; private final ClientID clientId; private final ClientAuthentication clientAuth; @@ -84,40 +79,34 @@ public class OpenIdProvider { @Inject public OpenIdProvider( Config config, LoginService loginService, HttpClient httpClient, ObjectMapper objectMapper - ) throws InterruptedException, IOException { - this.loginService = loginService; - - force = config.getBoolean(Keys.OPENID_FORCE); - clientId = new ClientID(config.getString(Keys.OPENID_CLIENT_ID)); - clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENT_SECRET))); - - try { - callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); - baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - - if (config.hasKey(Keys.OPENID_ISSUER_URL)) { - HttpRequest httpRequest = HttpRequest.newBuilder( - URI.create(config.getString(Keys.OPENID_ISSUER_URL) + "/.well-known/openid-configuration")) - .header("Accept", "application/json") - .build(); - - String httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); - - Map discoveryMap = objectMapper.readValue( - httpResponse, new TypeReference>() { }); - - authUrl = new URI((String) discoveryMap.get("authorization_endpoint")); - tokenUrl = new URI((String) discoveryMap.get("token_endpoint")); - userInfoUrl = new URI((String) discoveryMap.get("userinfo_endpoint")); - - LOGGER.info("OpenID Connect auto discovery successful"); - } else { - authUrl = new URI(config.getString(Keys.OPENID_AUTH_URL)); - tokenUrl = new URI(config.getString(Keys.OPENID_TOKEN_URL)); - userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFO_URL)); - } - } catch (URISyntaxException error) { - LOGGER.error("Invalid URIs provided in OpenID configuration"); + ) throws InterruptedException, IOException, URISyntaxException { + this.loginService = loginService; + + force = config.getBoolean(Keys.OPENID_FORCE); + clientId = new ClientID(config.getString(Keys.OPENID_CLIENT_ID)); + clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENT_SECRET))); + + callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); + baseUrl = new URI(config.getString(Keys.WEB_URL, "")); + + if (config.hasKey(Keys.OPENID_ISSUER_URL)) { + HttpRequest httpRequest = HttpRequest.newBuilder( + URI.create(config.getString(Keys.OPENID_ISSUER_URL) + "/.well-known/openid-configuration")) + .header("Accept", "application/json") + .build(); + + String httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); + + Map discoveryMap = objectMapper.readValue( + httpResponse, new TypeReference>() { }); + + authUrl = new URI((String) discoveryMap.get("authorization_endpoint")); + tokenUrl = new URI((String) discoveryMap.get("token_endpoint")); + userInfoUrl = new URI((String) discoveryMap.get("userinfo_endpoint")); + } else { + authUrl = new URI(config.getString(Keys.OPENID_AUTH_URL)); + tokenUrl = new URI(config.getString(Keys.OPENID_TOKEN_URL)); + userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFO_URL)); } adminGroup = config.getString(Keys.OPENID_ADMIN_GROUP); -- cgit v1.2.3 From c0dd2a6187de517af33aa92e0524414e65d973b4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 5 Apr 2023 22:27:02 +0100 Subject: Rename ServletHelper to WebHelper --- src/main/java/org/traccar/MainModule.java | 15 +------ .../org/traccar/api/resource/SessionResource.java | 14 +++--- .../java/org/traccar/database/OpenIdProvider.java | 6 +-- .../java/org/traccar/helper/ServletHelper.java | 45 ------------------- src/main/java/org/traccar/helper/WebHelper.java | 51 ++++++++++++++++++++++ .../java/org/traccar/helper/ServletHelperTest.java | 39 ----------------- .../java/org/traccar/helper/WebHelperTest.java | 39 +++++++++++++++++ 7 files changed, 102 insertions(+), 107 deletions(-) delete mode 100644 src/main/java/org/traccar/helper/ServletHelper.java create mode 100644 src/main/java/org/traccar/helper/WebHelper.java delete mode 100644 src/test/java/org/traccar/helper/ServletHelperTest.java create mode 100644 src/test/java/org/traccar/helper/WebHelperTest.java diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 4db6e0e32..41124bd03 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -75,6 +75,7 @@ import org.traccar.handler.GeolocationHandler; import org.traccar.handler.SpeedLimitHandler; import org.traccar.helper.ObjectMapperContextResolver; import org.traccar.helper.SanitizerModule; +import org.traccar.helper.WebHelper; import org.traccar.mail.LogMailManager; import org.traccar.mail.MailManager; import org.traccar.mail.SmtpMailManager; @@ -390,19 +391,7 @@ public class MainModule extends AbstractModule { public static VelocityEngine provideVelocityEngine(Config config) { Properties properties = new Properties(); properties.setProperty("resource.loader.file.path", config.getString(Keys.TEMPLATES_ROOT) + "/"); - - if (config.hasKey(Keys.WEB_URL)) { - properties.setProperty("web.url", config.getString(Keys.WEB_URL).replaceAll("/$", "")); - } else { - String address; - try { - address = config.getString(Keys.WEB_ADDRESS, InetAddress.getLocalHost().getHostAddress()); - } catch (UnknownHostException e) { - address = "localhost"; - } - String url = URIUtil.newURI("http", address, config.getInteger(Keys.WEB_PORT), "", ""); - properties.setProperty("web.url", url); - } + properties.setProperty("web.url", WebHelper.retrieveWebUrl(config)); VelocityEngine velocityEngine = new VelocityEngine(); velocityEngine.init(properties); diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index ac39fa449..9b6a74ddb 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -21,7 +21,7 @@ import org.traccar.api.signature.TokenManager; import org.traccar.database.OpenIdProvider; import org.traccar.helper.DataConverter; import org.traccar.helper.LogAction; -import org.traccar.helper.ServletHelper; +import org.traccar.helper.WebHelper; import org.traccar.model.User; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; @@ -84,7 +84,7 @@ public class SessionResource extends BaseResource { User user = loginService.login(token); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return user; } } @@ -111,7 +111,7 @@ public class SessionResource extends BaseResource { User user = loginService.login(email, password); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return user; } } @@ -135,7 +135,7 @@ public class SessionResource extends BaseResource { User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Equals("id", userId))); request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return user; } @@ -146,17 +146,17 @@ public class SessionResource extends BaseResource { User user = loginService.login(email, password); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return user; } else { - LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request)); + LogAction.failedLogin(WebHelper.retrieveRemoteAddress(request)); throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); } } @DELETE public Response remove() { - LogAction.logout(getUserId(), ServletHelper.retrieveRemoteAddress(request)); + LogAction.logout(getUserId(), WebHelper.retrieveRemoteAddress(request)); request.getSession().removeAttribute(USER_ID_KEY); return Response.noContent().build(); } diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 941d0e587..6550a1278 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -22,7 +22,7 @@ import org.traccar.api.security.LoginService; import org.traccar.model.User; import org.traccar.storage.StorageException; import org.traccar.helper.LogAction; -import org.traccar.helper.ServletHelper; +import org.traccar.helper.WebHelper; import java.net.URI; import java.net.URISyntaxException; @@ -88,7 +88,7 @@ public class OpenIdProvider { callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - + if (config.hasKey(Keys.OPENID_ISSUER_URL)) { HttpRequest httpRequest = HttpRequest.newBuilder( URI.create(config.getString(Keys.OPENID_ISSUER_URL) + "/.well-known/openid-configuration")) @@ -192,7 +192,7 @@ public class OpenIdProvider { User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), administrator); request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return baseUrl; } diff --git a/src/main/java/org/traccar/helper/ServletHelper.java b/src/main/java/org/traccar/helper/ServletHelper.java deleted file mode 100644 index b6c587ec3..000000000 --- a/src/main/java/org/traccar/helper/ServletHelper.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2020 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.helper; - -import javax.servlet.http.HttpServletRequest; - -public final class ServletHelper { - - private ServletHelper() { - } - - public static String retrieveRemoteAddress(HttpServletRequest request) { - - if (request != null) { - String remoteAddress = request.getHeader("X-FORWARDED-FOR"); - - if (remoteAddress != null && !remoteAddress.isEmpty()) { - int separatorIndex = remoteAddress.indexOf(","); - if (separatorIndex > 0) { - return remoteAddress.substring(0, separatorIndex); // remove the additional data - } else { - return remoteAddress; - } - } else { - return request.getRemoteAddr(); - } - } else { - return null; - } - } - -} diff --git a/src/main/java/org/traccar/helper/WebHelper.java b/src/main/java/org/traccar/helper/WebHelper.java new file mode 100644 index 000000000..9c6547d8d --- /dev/null +++ b/src/main/java/org/traccar/helper/WebHelper.java @@ -0,0 +1,51 @@ +/* + * Copyright 2020 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.helper; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.util.URIUtil; +import org.traccar.config.Config; +import org.traccar.config.Keys; + +public final class WebHelper { + + private WebHelper() { + } + + public static String retrieveRemoteAddress(HttpServletRequest request) { + + if (request != null) { + String remoteAddress = request.getHeader("X-FORWARDED-FOR"); + + if (remoteAddress != null && !remoteAddress.isEmpty()) { + int separatorIndex = remoteAddress.indexOf(","); + if (separatorIndex > 0) { + return remoteAddress.substring(0, separatorIndex); // remove the additional data + } else { + return remoteAddress; + } + } else { + return request.getRemoteAddr(); + } + } else { + return null; + } + } +} diff --git a/src/test/java/org/traccar/helper/ServletHelperTest.java b/src/test/java/org/traccar/helper/ServletHelperTest.java deleted file mode 100644 index 3a645bc36..000000000 --- a/src/test/java/org/traccar/helper/ServletHelperTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.traccar.helper; - -import org.junit.jupiter.api.Test; - -import javax.servlet.http.HttpServletRequest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class ServletHelperTest { - - @Test - public void testRetrieveRemoteAddressProxyMultiple() { - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getRemoteAddr()).thenReturn("147.120.1.5"); - when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65, 10.20.10.33, 10.20.20.34"); - - assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request)); - } - - @Test - public void testRetrieveRemoteAddressProxySingle() { - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getRemoteAddr()).thenReturn("147.120.1.5"); - when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65"); - - assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request)); - } - - @Test - public void testRetrieveRemoteAddressNoProxy() { - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getRemoteAddr()).thenReturn("231.23.45.65"); - - assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request)); - } - -} diff --git a/src/test/java/org/traccar/helper/WebHelperTest.java b/src/test/java/org/traccar/helper/WebHelperTest.java new file mode 100644 index 000000000..3a7329cb8 --- /dev/null +++ b/src/test/java/org/traccar/helper/WebHelperTest.java @@ -0,0 +1,39 @@ +package org.traccar.helper; + +import org.junit.jupiter.api.Test; + +import javax.servlet.http.HttpServletRequest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class WebHelperTest { + + @Test + public void testRetrieveRemoteAddressProxyMultiple() { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRemoteAddr()).thenReturn("147.120.1.5"); + when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65, 10.20.10.33, 10.20.20.34"); + + assertEquals("231.23.45.65", WebHelper.retrieveRemoteAddress(request)); + } + + @Test + public void testRetrieveRemoteAddressProxySingle() { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRemoteAddr()).thenReturn("147.120.1.5"); + when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65"); + + assertEquals("231.23.45.65", WebHelper.retrieveRemoteAddress(request)); + } + + @Test + public void testRetrieveRemoteAddressNoProxy() { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRemoteAddr()).thenReturn("231.23.45.65"); + + assertEquals("231.23.45.65", WebHelper.retrieveRemoteAddress(request)); + } + +} -- cgit v1.2.3 From 88a56f29fff1ab252a2c415f0d44a22192dd6b66 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 5 Apr 2023 22:29:32 +0100 Subject: Implement retrieveWebUrl --- src/main/java/org/traccar/MainModule.java | 3 --- src/main/java/org/traccar/database/OpenIdProvider.java | 6 +++--- src/main/java/org/traccar/helper/WebHelper.java | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 41124bd03..6a2fe21c3 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -26,7 +26,6 @@ import com.google.inject.name.Names; import io.netty.util.HashedWheelTimer; import io.netty.util.Timer; import org.apache.velocity.app.VelocityEngine; -import org.eclipse.jetty.util.URIUtil; import org.traccar.broadcast.BroadcastService; import org.traccar.broadcast.MulticastBroadcastService; import org.traccar.broadcast.NullBroadcastService; @@ -96,9 +95,7 @@ import javax.inject.Singleton; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import java.io.IOException; -import java.net.InetAddress; import java.net.URISyntaxException; -import java.net.UnknownHostException; import java.net.http.HttpClient; import java.util.Properties; diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 6550a1278..d0ec4e98d 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -86,9 +86,9 @@ public class OpenIdProvider { clientId = new ClientID(config.getString(Keys.OPENID_CLIENT_ID)); clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENT_SECRET))); - callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback"); - baseUrl = new URI(config.getString(Keys.WEB_URL, "")); - + baseUrl = new URI(WebHelper.retrieveWebUrl(config)); + callbackUrl = new URI(WebHelper.retrieveWebUrl(config) + "/api/session/openid/callback"); + if (config.hasKey(Keys.OPENID_ISSUER_URL)) { HttpRequest httpRequest = HttpRequest.newBuilder( URI.create(config.getString(Keys.OPENID_ISSUER_URL) + "/.well-known/openid-configuration")) diff --git a/src/main/java/org/traccar/helper/WebHelper.java b/src/main/java/org/traccar/helper/WebHelper.java index 9c6547d8d..e2844bc4d 100644 --- a/src/main/java/org/traccar/helper/WebHelper.java +++ b/src/main/java/org/traccar/helper/WebHelper.java @@ -48,4 +48,18 @@ public final class WebHelper { return null; } } + + public static String retrieveWebUrl(Config config) { + if (config.hasKey(Keys.WEB_URL)) { + return config.getString(Keys.WEB_URL).replaceAll("/$", ""); + } else { + String address; + try { + address = config.getString(Keys.WEB_ADDRESS, InetAddress.getLocalHost().getHostAddress()); + } catch (UnknownHostException e) { + address = "localhost"; + } + return URIUtil.newURI("http", address, config.getInteger(Keys.WEB_PORT), "", ""); + } + } } -- cgit v1.2.3 From 4ece72558c80038728fa67ec51238bac48fc4d64 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 6 Apr 2023 07:38:08 -0700 Subject: Support GS-404 driver id --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 8 ++++++-- .../java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index ead657893..4968ed05e 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -610,8 +610,12 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { int length = buf.readInt() - 4; getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); if (isPrintable(buf, length)) { - position.set(Position.KEY_RESULT, - buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim()); + String data = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim(); + if (data.startsWith("GTSL")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, data.split("\\|")[4]); + } else { + position.set(Position.KEY_RESULT, data); + } } else { position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(buf.readSlice(length))); diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java index 60b58f626..0b4f1d243 100644 --- a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -3,6 +3,7 @@ package org.traccar.protocol; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class TeltonikaProtocolDecoderTest extends ProtocolTest { @@ -14,6 +15,10 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "000F313233343536373839303132333435")); + verifyAttribute(decoder, binary( + "00000000000000240d01060000001c642b3ad14754534c7c367c317c307c31323734393838347c317c0d0a010000ec11"), + Position.KEY_DRIVER_UNIQUE_ID, "12749884"); + verifyPositions(decoder, binary( "00000000000000a28e0100000183ac617e3001123eb99b1e142db4000000000000000000001d000900f000005000001503004500011e1801212d01242a012722012a18001100b5000000b600000018000000cd151000431c2d011f6981012047d701226981012347d901256981012647d8012869810129e6f304b0000304b1000304b2000304b30003000100f10000639d0002000b0000000214bf12fe000e0000000029d18c95000001000051b6")); -- cgit v1.2.3 From 5da3b8fcb480736161aa6a0896501f00f197bc13 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 6 Apr 2023 19:39:56 -0700 Subject: Decode 808 battery level --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 1 + src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index f13299169..1aebba4e6 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -538,6 +538,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); break; case 0xD4: + case 0xE1: position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); break; case 0xD5: diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 4541185f4..67f214563 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyAttribute(decoder, binary( + "7e0200002f017028775424038d000000000000000a0189dbeb04ca653a00000012014723040700074401040000000030011b31010ee1012dea020001dc7e"), + Position.KEY_BATTERY_LEVEL, 45); + verifyAttribute(decoder, binary( "7E02000079013653183645009E00000000000C0C030158BF0006C926670000004000CE22120904274201040000005DBC3244524956494E47204C4943454E53452454455354244D522E0000000000000000000000000000000000000000000000000000BD0F323431393939393935383030313030E3060000050500007102000C30011F310108987E"), "driver", "DRIVING LICENSE$TEST$MR."); -- cgit v1.2.3 From ddf44c40b95c4a4a013f244ddffa3b1fad39d416 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 7 Apr 2023 07:01:27 -0700 Subject: Set LTE radio type --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 4968ed05e..969b24297 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -371,18 +371,19 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { Long cid4g = (Long) position.getAttributes().remove("cid4g"); Integer lac = (Integer) position.getAttributes().remove("lac"); if (lac != null && (cid2g != null || cid4g != null)) { + Network network = new Network(); CellTower cellTower; if (cid2g != null) { cellTower = CellTower.fromLacCid(getConfig(), lac, cid2g); - cellTower.setRadioType("gsm"); } else { cellTower = CellTower.fromLacCid(getConfig(), lac, cid4g); - cellTower.setRadioType("lte"); + network.setRadioType("lte"); } long operator = position.getInteger(Position.KEY_OPERATOR); if (operator >= 1000) { cellTower.setOperator(operator); } + network.addCellTower(cellTower); position.setNetwork(new Network(cellTower)); } } -- cgit v1.2.3 From ee39f67d21078da595a819255b59d88c30e66d7a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 9 Apr 2023 07:50:58 -0700 Subject: Upgrade JEXL version --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index c29f3ba26..a0be04f8c 100644 --- a/build.gradle +++ b/build.gradle @@ -69,6 +69,7 @@ dependencies { implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion" implementation "org.liquibase:liquibase-core:4.19.0" implementation "com.sun.mail:jakarta.mail:1.6.7" + implementation "org.apache.commons:commons-jexl3:3.3" implementation "org.jxls:jxls:$jxlsVersion" implementation "org.jxls:jxls-poi:$jxlsVersion" implementation "org.apache.velocity:velocity-engine-core:2.3" -- cgit v1.2.3 From dd8c46eec3282e344eeea5e27d084448c85e1518 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 10 Apr 2023 19:40:22 -0700 Subject: Add raw data forwarding --- src/main/java/org/traccar/BasePipelineFactory.java | 13 ++++- src/main/java/org/traccar/config/Keys.java | 7 +++ .../java/org/traccar/forward/NetworkForwarder.java | 66 ++++++++++++++++++++++ .../traccar/handler/NetworkForwarderHandler.java | 64 +++++++++++++++++++++ 4 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/traccar/forward/NetworkForwarder.java create mode 100644 src/main/java/org/traccar/handler/NetworkForwarderHandler.java diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index 70f999c72..38b077980 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -36,6 +36,7 @@ import org.traccar.handler.GeocoderHandler; import org.traccar.handler.GeolocationHandler; import org.traccar.handler.HemisphereHandler; import org.traccar.handler.MotionHandler; +import org.traccar.handler.NetworkForwarderHandler; import org.traccar.handler.NetworkMessageHandler; import org.traccar.handler.OpenChannelHandler; import org.traccar.handler.RemoteAddressHandler; @@ -60,15 +61,15 @@ public abstract class BasePipelineFactory extends ChannelInitializer { private final Injector injector; private final TrackerConnector connector; + private final Config config; private final String protocol; - private final boolean instantAcknowledgement; private final int timeout; public BasePipelineFactory(TrackerConnector connector, Config config, String protocol) { this.injector = Main.getInjector(); this.connector = connector; + this.config = config; this.protocol = protocol; - instantAcknowledgement = config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT); int timeout = config.getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol)); if (timeout == 0) { this.timeout = config.getInteger(Keys.SERVER_TIMEOUT); @@ -115,9 +116,15 @@ public abstract class BasePipelineFactory extends ChannelInitializer { pipeline.addLast(new IdleStateHandler(timeout, 0, 0)); } pipeline.addLast(new OpenChannelHandler(connector)); + if (config.hasKey(Keys.SERVER_FORWARD)) { + int port = config.getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol)); + var handler = new NetworkForwarderHandler(port); + injector.injectMembers(handler); + pipeline.addLast(handler); + } pipeline.addLast(new NetworkMessageHandler()); pipeline.addLast(new StandardLoggingHandler(protocol)); - if (!instantAcknowledgement) { + if (!config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) { pipeline.addLast(new AcknowledgementHandler()); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index b97acfd66..8ced32153 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -805,6 +805,13 @@ public final class Keys { List.of(KeyType.CONFIG), "max-age=3600,public"); + /** + * Host for raw data forwarding. + */ + public static final ConfigKey SERVER_FORWARD = new StringConfigKey( + "server.forward", + List.of(KeyType.CONFIG)); + /** * Position forwarding format. Available options are "url", "json" and "kafka". Default is "url". */ diff --git a/src/main/java/org/traccar/forward/NetworkForwarder.java b/src/main/java/org/traccar/forward/NetworkForwarder.java new file mode 100644 index 000000000..6abf2b7ba --- /dev/null +++ b/src/main/java/org/traccar/forward/NetworkForwarder.java @@ -0,0 +1,66 @@ +/* + * 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.forward; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; + +@Singleton +public class NetworkForwarder { + + private static final Logger LOGGER = LoggerFactory.getLogger(NetworkForwarder.class); + + private final InetAddress destination; + private final DatagramSocket connectionUdp; + private final Map connectionsTcp = new HashMap<>(); + + @Inject + public NetworkForwarder(Config config) throws IOException { + destination = InetAddress.getByName(config.getString(Keys.SERVER_FORWARD)); + connectionUdp = new DatagramSocket(); + } + + public void forward(InetSocketAddress source, int port, boolean datagram, byte[] data) { + try { + if (datagram) { + connectionUdp.send(new DatagramPacket(data, data.length, destination, port)); + } else { + Socket connectionTcp = connectionsTcp.get(source); + if (connectionTcp == null || connectionTcp.isClosed()) { + connectionTcp = new Socket(destination, port); + connectionsTcp.put(source, connectionTcp); + } + connectionTcp.getOutputStream().write(data); + } + } catch (IOException e) { + LOGGER.warn("Network forwarding error", e); + } + } + +} diff --git a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java new file mode 100644 index 000000000..a3792a3e5 --- /dev/null +++ b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java @@ -0,0 +1,64 @@ +/* + * 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.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.DatagramPacket; +import org.traccar.forward.NetworkForwarder; + +import javax.inject.Inject; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +public class NetworkForwarderHandler extends ChannelInboundHandlerAdapter { + + private final int port; + + private NetworkForwarder networkForwarder; + + public NetworkForwarderHandler(int port) { + this.port = port; + } + + @Inject + public void setNetworkForwarder(NetworkForwarder networkForwarder) { + this.networkForwarder = networkForwarder; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + boolean datagram = ctx.channel() instanceof DatagramChannel; + SocketAddress remoteAddress; + ByteBuf buffer; + if (datagram) { + DatagramPacket message = (DatagramPacket) msg; + remoteAddress = message.recipient(); + buffer = message.content(); + } else { + remoteAddress = ctx.channel().remoteAddress(); + buffer = (ByteBuf) msg; + } + + byte[] data = new byte[buffer.readableBytes()]; + buffer.getBytes(buffer.readerIndex(), data); + networkForwarder.forward((InetSocketAddress) remoteAddress, port, datagram, data); + super.channelRead(ctx, msg); + } + +} -- cgit v1.2.3 From d41d34de83ed755e0a51e5638e121391f84b275f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 11 Apr 2023 17:33:14 -0700 Subject: Support Nano firmware update --- .../org/traccar/protocol/Minifinder2Protocol.java | 6 +- .../protocol/Minifinder2ProtocolEncoder.java | 66 ++++++++++++++++++++++ .../protocol/Minifinder2ProtocolEncoderTest.java | 29 ++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java create mode 100644 src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java diff --git a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java index 5499a274e..61a43d8db 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java +++ b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -20,6 +20,7 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.model.Command; import java.nio.ByteOrder; @@ -29,10 +30,13 @@ public class Minifinder2Protocol extends BaseProtocol { @Inject public Minifinder2Protocol(Config config) { + setSupportedDataCommands( + Command.TYPE_FIRMWARE_UPDATE); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1200, 2, 2, 4, 0, true)); + pipeline.addLast(new Minifinder2ProtocolEncoder(Minifinder2Protocol.this)); pipeline.addLast(new Minifinder2ProtocolDecoder(Minifinder2Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java new file mode 100644 index 000000000..ce7de6dfc --- /dev/null +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java @@ -0,0 +1,66 @@ +/* + * 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.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; +import org.traccar.model.Device; + +import java.nio.charset.StandardCharsets; + +public class Minifinder2ProtocolEncoder extends BaseProtocolEncoder { + + public Minifinder2ProtocolEncoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf encodeContent(ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte(0xAB); // header + buf.writeByte(0x00); // properties + buf.writeShortLE(content.readableBytes()); + buf.writeShortLE(Checksum.crc16(Checksum.CRC16_XMODEM, content.nioBuffer())); + buf.writeShortLE(1); // index + buf.writeBytes(content); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + Device device = getCacheManager().getObject(Device.class, command.getDeviceId()); + if ("Nano".equalsIgnoreCase(device.getModel())) { + ByteBuf content = Unpooled.buffer(); + if (command.getType().equals(Command.TYPE_FIRMWARE_UPDATE)) { + String url = command.getString(Command.KEY_DATA); + content.writeByte(1 + url.length()); + content.writeByte(0x30); // type + content.writeCharSequence(url, StandardCharsets.US_ASCII); + return encodeContent(content); + } + } + + return null; + } + +} diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java new file mode 100644 index 000000000..a3477bfe8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java @@ -0,0 +1,29 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; +import org.traccar.model.Device; + +import static org.mockito.Mockito.when; + +public class Minifinder2ProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncodeNano() throws Exception { + + var encoder = inject(new Minifinder2ProtocolEncoder(null)); + + var device = encoder.getCacheManager().getObject(Device.class, 1); + when(device.getModel()).thenReturn("Nano"); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_FIRMWARE_UPDATE); + command.set(Command.KEY_DATA, "https://example.com"); + + verifyCommand(encoder, command, binary("ab00150018750100143068747470733a2f2f6578616d706c652e636f6d")); + + } + +} -- cgit v1.2.3 From 5460739293ccd8e89adc9edb4653b4de28b09897 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 11 Apr 2023 19:28:43 -0700 Subject: Handle closed connections --- src/main/java/org/traccar/forward/NetworkForwarder.java | 11 +++++++++++ .../java/org/traccar/handler/NetworkForwarderHandler.java | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/src/main/java/org/traccar/forward/NetworkForwarder.java b/src/main/java/org/traccar/forward/NetworkForwarder.java index 6abf2b7ba..0915aaa27 100644 --- a/src/main/java/org/traccar/forward/NetworkForwarder.java +++ b/src/main/java/org/traccar/forward/NetworkForwarder.java @@ -63,4 +63,15 @@ public class NetworkForwarder { } } + public void disconnect(InetSocketAddress source) { + Socket connectionTcp = connectionsTcp.remove(source); + if (connectionTcp != null) { + try { + connectionTcp.close(); + } catch (IOException e) { + LOGGER.warn("Connection close error", e); + } + } + } + } diff --git a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java index a3792a3e5..2c586c973 100644 --- a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java +++ b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java @@ -61,4 +61,12 @@ public class NetworkForwarderHandler extends ChannelInboundHandlerAdapter { super.channelRead(ctx, msg); } + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (!(ctx.channel() instanceof DatagramChannel)) { + networkForwarder.disconnect((InetSocketAddress) ctx.channel().remoteAddress()); + } + super.channelInactive(ctx); + } + } -- cgit v1.2.3 From 9a427527da45e599a1082f1f2836d195ea26acb5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 12 Apr 2023 17:14:22 -0700 Subject: Add iStartek SOS and door --- src/main/java/org/traccar/protocol/StartekProtocolDecoder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java index d75da7fbd..d08bb92a8 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -98,6 +98,8 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { private String decodeAlarm(int value) { switch (value) { + case 1: + return Position.ALARM_SOS; case 5: case 6: return Position.ALARM_DOOR; @@ -186,6 +188,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { int input = parser.nextHexInt(); int output = parser.nextHexInt(); position.set(Position.KEY_IGNITION, BitUtil.check(input, 1)); + position.set(Position.KEY_DOOR, BitUtil.check(input, 2)); position.set(Position.KEY_INPUT, input); position.set(Position.KEY_OUTPUT, output); -- cgit v1.2.3 From c024d09744dea2db2d60f51bc6c1532284ffca4e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Apr 2023 07:37:52 -0700 Subject: Fix Nano firmware update --- src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java | 2 ++ src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java | 1 + src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 37e86e243..f660f2e92 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -48,6 +48,8 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_DATA = 0x01; public static final int MSG_CONFIGURATION = 0x02; public static final int MSG_SERVICES = 0x03; + public static final int MSG_SYSTEM_CONTROL = 0x04; + public static final int MSG_FIRMWARE = 0x7E; public static final int MSG_RESPONSE = 0x7F; private String decodeAlarm(long code) { diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java index ce7de6dfc..fab3c3a6d 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java @@ -53,6 +53,7 @@ public class Minifinder2ProtocolEncoder extends BaseProtocolEncoder { ByteBuf content = Unpooled.buffer(); if (command.getType().equals(Command.TYPE_FIRMWARE_UPDATE)) { String url = command.getString(Command.KEY_DATA); + content.writeByte(Minifinder2ProtocolDecoder.MSG_SYSTEM_CONTROL); content.writeByte(1 + url.length()); content.writeByte(0x30); // type content.writeCharSequence(url, StandardCharsets.US_ASCII); diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java index a3477bfe8..ef6ff6dd9 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java @@ -22,7 +22,7 @@ public class Minifinder2ProtocolEncoderTest extends ProtocolTest { command.setType(Command.TYPE_FIRMWARE_UPDATE); command.set(Command.KEY_DATA, "https://example.com"); - verifyCommand(encoder, command, binary("ab00150018750100143068747470733a2f2f6578616d706c652e636f6d")); + verifyCommand(encoder, command, binary("ab00160059d2010004143068747470733a2f2f6578616d706c652e636f6d")); } -- cgit v1.2.3 From d898163368bdaaee17a2982ec219e997fd0c9b1f Mon Sep 17 00:00:00 2001 From: gustavofarias Date: Sat, 15 Apr 2023 16:33:54 -0300 Subject: Translate camel case names of alarms into proper readable names. --- templates/full/alarm.vm | 80 +++++++++++++++++++++++++++++++++++++++++++++++- templates/short/alarm.vm | 80 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/templates/full/alarm.vm b/templates/full/alarm.vm index 9fae1f13b..fb596ecde 100644 --- a/templates/full/alarm.vm +++ b/templates/full/alarm.vm @@ -1,9 +1,87 @@ #set($subject = "$device.name: alarm!") +#set($alarmName = $position.getString("alarm")) +#if( $alarmName == "general") + #set($alarmName = "General") +#elseif($alarmName == "sos") + #set($alarmName = "SOS") +#elseif($alarmName == "vibration") + #set($alarmName = "Vibration") +#elseif($alarmName == "movement") + #set($alarmName = "Movement") +#elseif($alarmName == "lowspeed") + #set($alarmName = "Low Speed") +#elseif($alarmName == "overspeed") + #set($alarmName = "Overspeed") +#elseif($alarmName == "fallDown") + #set($alarmName = "Fall Down") +#elseif($alarmName == "lowPower") + #set($alarmName = "Low Power") +#elseif($alarmName == "lowBattery") + #set($alarmName = "Low Battery") +#elseif($alarmName == "fault") + #set($alarmName = "Fault") +#elseif($alarmName == "powerOff") + #set($alarmName = "Power Off") +#elseif($alarmName == "powerOn") + #set($alarmName = "Power On") +#elseif($alarmName == "door") + #set($alarmName = "Door") +#elseif($alarmName == "lock") + #set($alarmName = "Lock") +#elseif($alarmName == "unlock") + #set($alarmName = "Unlock") +#elseif($alarmName == "geofence") + #set($alarmName = "Geofence") +#elseif($alarmName == "geofenceEnter") + #set($alarmName = "Geofence Enter") +#elseif($alarmName == "geofenceExit") + #set($alarmName = "Geofence Exit") +#elseif($alarmName == "gpsAntennaCut") + #set($alarmName = "GPS Antenna Cut") +#elseif($alarmName == "accident") + #set($alarmName = "Accident") +#elseif($alarmName == "tow") + #set($alarmName = "Tow") +#elseif($alarmName == "idle") + #set($alarmName = "Idle") +#elseif($alarmName == "highRpm") + #set($alarmName = "High RPM") +#elseif($alarmName == "hardAcceleration") + #set($alarmName = "Hard Acceleration") +#elseif($alarmName == "hardBraking") + #set($alarmName = "Hard Braking") +#elseif($alarmName == "hardCornering") + #set($alarmName = "Hard Cornering") +#elseif($alarmName == "laneChange") + #set($alarmName = "Lane Change") +#elseif($alarmName == "fatigueDriving") + #set($alarmName = "Fatigue Driving") +#elseif($alarmName == "powerCut") + #set($alarmName = "Power Cut") +#elseif($alarmName == "powerRestored") + #set($alarmName = "Power Restored") +#elseif($alarmName == "jamming") + #set($alarmName = "Jamming") +#elseif($alarmName == "temperature") + #set($alarmName = "Temperature") +#elseif($alarmName == "parking") + #set($alarmName = "Parking") +#elseif($alarmName == "bonnet") + #set($alarmName = "Bonnet") +#elseif($alarmName == "footBrake") + #set($alarmName = "Foot Brake") +#elseif($alarmName == "fuelLeak") + #set($alarmName = "Fuel Leak") +#elseif($alarmName == "tampering") + #set($alarmName = "Tampering") +#elseif($alarmName == "removing") + #set($alarmName = "Removing") +#end Device: $device.name
-Alarm: $position.getString("alarm")
+Alarm: $alarmName
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
Point: #{if}($position.address)$position.address#{else}$position.latitude°, $position.longitude°#{end}

diff --git a/templates/short/alarm.vm b/templates/short/alarm.vm index 15970dab8..effcb8f15 100644 --- a/templates/short/alarm.vm +++ b/templates/short/alarm.vm @@ -1,2 +1,80 @@ #set($subject = "$device.name: alarm!") -$device.name alarm: $position.getString("alarm") at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone) +#set($alarmName = $position.getString("alarm")) +#if( $alarmName == "general") + #set($alarmName = "General") +#elseif($alarmName == "sos") + #set($alarmName = "SOS") +#elseif($alarmName == "vibration") + #set($alarmName = "Vibration") +#elseif($alarmName == "movement") + #set($alarmName = "Movement") +#elseif($alarmName == "lowspeed") + #set($alarmName = "Low Speed") +#elseif($alarmName == "overspeed") + #set($alarmName = "Overspeed") +#elseif($alarmName == "fallDown") + #set($alarmName = "Fall Down") +#elseif($alarmName == "lowPower") + #set($alarmName = "Low Power") +#elseif($alarmName == "lowBattery") + #set($alarmName = "Low Battery") +#elseif($alarmName == "fault") + #set($alarmName = "Fault") +#elseif($alarmName == "powerOff") + #set($alarmName = "Power Off") +#elseif($alarmName == "powerOn") + #set($alarmName = "Power On") +#elseif($alarmName == "door") + #set($alarmName = "Door") +#elseif($alarmName == "lock") + #set($alarmName = "Lock") +#elseif($alarmName == "unlock") + #set($alarmName = "Unlock") +#elseif($alarmName == "geofence") + #set($alarmName = "Geofence") +#elseif($alarmName == "geofenceEnter") + #set($alarmName = "Geofence Enter") +#elseif($alarmName == "geofenceExit") + #set($alarmName = "Geofence Exit") +#elseif($alarmName == "gpsAntennaCut") + #set($alarmName = "GPS Antenna Cut") +#elseif($alarmName == "accident") + #set($alarmName = "Accident") +#elseif($alarmName == "tow") + #set($alarmName = "Tow") +#elseif($alarmName == "idle") + #set($alarmName = "Idle") +#elseif($alarmName == "highRpm") + #set($alarmName = "High RPM") +#elseif($alarmName == "hardAcceleration") + #set($alarmName = "Hard Acceleration") +#elseif($alarmName == "hardBraking") + #set($alarmName = "Hard Braking") +#elseif($alarmName == "hardCornering") + #set($alarmName = "Hard Cornering") +#elseif($alarmName == "laneChange") + #set($alarmName = "Lane Change") +#elseif($alarmName == "fatigueDriving") + #set($alarmName = "Fatigue Driving") +#elseif($alarmName == "powerCut") + #set($alarmName = "Power Cut") +#elseif($alarmName == "powerRestored") + #set($alarmName = "Power Restored") +#elseif($alarmName == "jamming") + #set($alarmName = "Jamming") +#elseif($alarmName == "temperature") + #set($alarmName = "Temperature") +#elseif($alarmName == "parking") + #set($alarmName = "Parking") +#elseif($alarmName == "bonnet") + #set($alarmName = "Bonnet") +#elseif($alarmName == "footBrake") + #set($alarmName = "Foot Brake") +#elseif($alarmName == "fuelLeak") + #set($alarmName = "Fuel Leak") +#elseif($alarmName == "tampering") + #set($alarmName = "Tampering") +#elseif($alarmName == "removing") + #set($alarmName = "Removing") +#end +$device.name alarm: $alarmName at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone) -- cgit v1.2.3 From 0a459e5206a29bd805c8d752361507b67dc6ff7e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 16 Apr 2023 07:55:15 -0700 Subject: Update Java dependencies --- build.gradle | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index a0be04f8c..da9c92ba9 100644 --- a/build.gradle +++ b/build.gradle @@ -27,10 +27,10 @@ enforce { ext { guiceVersion = "5.1.0" - jettyVersion = "10.0.13" // jetty 11 javax to jakarta - jerseyVersion = "2.38" // jersey 3 javax to jakarta - jacksonVersion = "2.13.3" // same version as jersey-media-json-jackson dependency - protobufVersion = "3.21.12" + jettyVersion = "10.0.15" // jetty 11 javax to jakarta + jerseyVersion = "2.39.1" // jersey 3 javax to jakarta + jacksonVersion = "2.14.1" // same version as jersey-media-json-jackson dependency + protobufVersion = "3.22.3" jxlsVersion = "2.12.0" junitVersion = "5.9.2" } @@ -45,11 +45,11 @@ dependencies { implementation "commons-codec:commons-codec:1.15" implementation "com.h2database:h2:2.1.214" implementation "com.mysql:mysql-connector-j:8.0.32" - implementation "org.postgresql:postgresql:42.5.3" + implementation "org.postgresql:postgresql:42.6.0" implementation "com.microsoft.sqlserver:mssql-jdbc:12.2.0.jre11" implementation "com.zaxxer:HikariCP:5.0.1" - implementation "io.netty:netty-all:4.1.87.Final" - implementation "org.slf4j:slf4j-jdk14:2.0.6" + implementation "io.netty:netty-all:4.1.91.Final" + implementation "org.slf4j:slf4j-jdk14:2.0.7" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" @@ -67,7 +67,7 @@ dependencies { implementation "org.glassfish.hk2:guice-bridge:2.6.1" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.19.0" + implementation "org.liquibase:liquibase-core:4.21.1" implementation "com.sun.mail:jakarta.mail:1.6.7" implementation "org.apache.commons:commons-jexl3:3.3" implementation "org.jxls:jxls:$jxlsVersion" @@ -75,22 +75,22 @@ dependencies { implementation "org.apache.velocity:velocity-engine-core:2.3" implementation "org.apache.velocity.tools:velocity-tools-generic:3.1" implementation "org.apache.commons:commons-collections4:4.4" - implementation "org.mnode.ical4j:ical4j:3.2.8" + implementation "org.mnode.ical4j:ical4j:3.2.11" implementation "org.locationtech.spatial4j:spatial4j:0.8" implementation "org.locationtech.jts:jts-core:1.19.0" implementation "net.java.dev.jna:jna-platform:5.13.0" implementation "com.github.jnr:jnr-posix:3.1.16" implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation "javax.activation:activation:1.1.1" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.399" - implementation "org.apache.kafka:kafka-clients:3.3.2" - implementation "com.hivemq:hivemq-mqtt-client:1.3.0" - implementation "redis.clients:jedis:4.3.1" + implementation "com.amazonaws:aws-java-sdk-sns:1.12.450" + implementation "org.apache.kafka:kafka-clients:3.4.0" + implementation "com.hivemq:hivemq-mqtt-client:1.3.1" + implementation "redis.clients:jedis:4.3.2" implementation "com.google.firebase:firebase-admin:9.1.1" implementation "com.nimbusds:oauth2-oidc-sdk:10.7.1" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:5.1.1" + testImplementation "org.mockito:mockito-core:5.3.0" } test { -- cgit v1.2.3 From 7b3aebb26d1f1ed8617db2b03e5c35a48bf44dba Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 16 Apr 2023 09:55:52 -0700 Subject: Update version number --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index da9c92ba9..1fa3986fd 100644 --- a/build.gradle +++ b/build.gradle @@ -107,7 +107,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.6", + "Implementation-Version": "5.7", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 09b94ee5e..821c90958 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.6 +AppVersion=5.7 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index 39bd6bd61..dde673e19 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.6", + "version": "5.7", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From 514605fc0070c7365e525141b6bdd64f5dffadc7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 16 Apr 2023 10:17:09 -0700 Subject: Add integration tests --- tools/test-integration.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/test-integration.py b/tools/test-integration.py index 9aad642ae..84d2fa2e3 100755 --- a/tools/test-integration.py +++ b/tools/test-integration.py @@ -121,6 +121,11 @@ messages = { 'startek': '&&o125,123456789012345,000,0,,210702235150,A,27.263505,153.037061,11,1.2,0,0,31,5125,505|1|7032|8C89802,20,0000002D,00,00,01E2|019DF0\r\n', 'hoopo': '{ "deviceId": "123456789012345", "assetName": "123456789012345", "assetType": "test", "eventData": { "latitude": 31.97498, "longitude": 34.80802, "locationName": "", "accuracyLevel": "High", "eventType": "Arrival", "batteryLevel": 100, "receiveTime": "2021-09-20T18:52:32Z" }, "eventTime": "2021-09-20T08:52:02Z", "serverReportTime": "0001-01-01T00:00:00Z" }', 'techtocruz': '$$A120,123456789012345,211005105836,A,FLEX,KCB 947C,000.0,0,-1.38047,S,36.93951,E,1648.4,243.140,21,28,12.1,3.7,0,1,0,0,0,*F6', + 'flexapi': '${"topic":"v1/123456789012345/motion/info","payload":{"motion.ts":1641885877,"motion.ax":0.006344,"motion.ay":0.289384,"motion.az":-0.939156,"motion.gx":0.420000,"motion.gy":0.420000,"motion.gz":-0.280000}}xx\r\n', + 'jido': '*123456789012345,03,130517,160435,1820.5845,N,07833.2478,E,1,58#', + 'armoli': '[M123456789012345210122125205N38.735641E035.4727751E003340000000C00000E9E07FF:106AG505283H60E];', + 'teratrack': '{"MDeviceID":"022043756090","DiviceType":"1","DataType":"1","DataLength":"69","DateTime":"2022-03-09 10:56:01","Latitude":"-6.846451","Longitude":"39.316324","LongitudeState":"1","LatitudeState":"0","Speed":"90","Mileage":"0","FenceAlarm":"0","AreaAlarmID":"0","LockCutOff":"0","SealTampered":"0","MessageAck":"1","LockRope":"1","LockStatus":"1","LockOpen":"0","PasswordError":"0","CardNo":"60000644","IllegalCard":"0","LowPower":"0","UnCoverBack":"0","CoverStatus":"1","LockStuck":"0","Power":"79","GSM":"16","IMEI":"123456789012345","Index":"20","Slave":[]}', + 'envotech': '$80SLM,02,F,123456,130410155921,431750216,000040,0000,,00000000,\'13041015592110476673N10111459E001281*2A#', } baseUrl = 'http://localhost:8082' -- cgit v1.2.3 From 94280e2e63b02ae67482c85a388a58add85e10cf Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 16 Apr 2023 12:54:38 -0700 Subject: Fix JXLS JEXL permissions --- .../reports/common/ExpressionEvaluatorFactory.java | 58 ++++++++++++++++++++++ .../org.jxls.expression.ExpressionEvaluatorFactory | 1 + 2 files changed, 59 insertions(+) create mode 100644 src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java create mode 100644 src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory diff --git a/src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java b/src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java new file mode 100644 index 000000000..8b139a572 --- /dev/null +++ b/src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java @@ -0,0 +1,58 @@ +package org.traccar.reports.common; + +import org.apache.commons.jexl3.JexlBuilder; +import org.apache.commons.jexl3.introspection.JexlPermissions; +import org.jxls.expression.ExpressionEvaluator; +import org.jxls.expression.JexlExpressionEvaluator; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class ExpressionEvaluatorFactory implements org.jxls.expression.ExpressionEvaluatorFactory { + + private final JexlPermissions permissions = new JexlPermissions() { + @Override + public boolean allow(Package pack) { + return true; + } + + @Override + public boolean allow(Class clazz) { + return true; + } + + @Override + public boolean allow(Constructor ctor) { + return true; + } + + @Override + public boolean allow(Method method) { + return true; + } + + @Override + public boolean allow(Field field) { + return true; + } + + @Override + public JexlPermissions compose(String... src) { + return this; + } + }; + + @Override + public ExpressionEvaluator createExpressionEvaluator(String expression) { + JexlExpressionEvaluator expressionEvaluator = expression == null + ? new JexlExpressionEvaluator() + : new JexlExpressionEvaluator(expression); + expressionEvaluator.setJexlEngine(new JexlBuilder() + .silent(true) + .strict(false) + .permissions(permissions) + .create()); + return expressionEvaluator; + } +} diff --git a/src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory b/src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory new file mode 100644 index 000000000..75d628857 --- /dev/null +++ b/src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory @@ -0,0 +1 @@ +org.traccar.reports.common.ExpressionEvaluatorFactory -- cgit v1.2.3 From f982ed08a3d21e8eb6e9bbf4c25698ecbaad5b37 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 16 Apr 2023 16:48:36 -0700 Subject: Update submodule --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 091d10531..74dc5065f 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 091d10531a59216c5f0a812609742e097c68ff2c +Subproject commit 74dc5065ffd3866d660fd7b908a26c5089173d08 -- cgit v1.2.3 From ab801e856521356ff7a33250e1abdb8857ef84b3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 19 Apr 2023 06:29:50 -0700 Subject: Fix group commands --- src/main/java/org/traccar/api/resource/CommandResource.java | 6 ++++-- tools/test-commands.py | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index 7ba1ee2b4..b69d4d9ac 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -28,6 +28,7 @@ import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Position; +import org.traccar.model.QueuedCommand; import org.traccar.model.Typed; import org.traccar.model.User; import org.traccar.model.UserRestrictions; @@ -121,8 +122,9 @@ public class CommandResource extends ExtendedObjectResource { permissionsService.checkPermission(Group.class, getUserId(), groupId); var devices = DeviceUtil.getAccessibleDevices(storage, getUserId(), List.of(), List.of(groupId)); for (Device device : devices) { - entity.setDeviceId(device.getId()); - result = result && commandsManager.sendCommand(entity); + Command command = QueuedCommand.fromCommand(entity).toCommand(); + command.setDeviceId(device.getId()); + result = result && commandsManager.sendCommand(command); } } else { permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); diff --git a/tools/test-commands.py b/tools/test-commands.py index 6e310051a..7efd963b4 100755 --- a/tools/test-commands.py +++ b/tools/test-commands.py @@ -6,9 +6,9 @@ import binascii s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 5001)) #s.send(binascii.unhexlify('68680f0504035889905831401700df1a00000d0a')) -s.send("imei:123456789012345,tracker,151030080103,,F,000101.000,A,5443.3834,N,02512.9071,E,0.00,0;") +s.send(b"imei:123456789012345,tracker,151030080103,,F,000101.000,A,5443.3834,N,02512.9071,E,0.00,0;") while True: - print s.recv(1024) + print(s.recv(1024)) s.close() -- cgit v1.2.3 From 1d31ebe88f2674252fc2ab043349b900db5e5e2d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 19 Apr 2023 08:52:10 -0700 Subject: Support BS51 messages --- .../org/traccar/protocol/Tk103ProtocolDecoder.java | 119 ++++++++++++++------- .../traccar/protocol/Tk103ProtocolDecoderTest.java | 3 + 2 files changed, 84 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java index 2b50e55c2..6c926da90 100644 --- a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java @@ -463,47 +463,90 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); - ByteBuf buf = Unpooled.wrappedBuffer( - DataConverter.parseHex(sentence.substring(1 + 12 + 4, sentence.length() - 1))); - - buf.readUnsignedByte(); - buf.readUnsignedByte(); - buf.readUnsignedByte(); // header - - int batteryCount = buf.readUnsignedByte(); - for (int i = 1; i <= 24; i++) { - int voltage = buf.readUnsignedShortLE(); - if (i <= batteryCount) { - position.set("battery" + i, voltage * 0.001); + String payload = sentence.substring(1 + 12 + 4, sentence.length() - 1); + + if (sentence.startsWith("BS50", 1 + 12)) { + + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(payload)); + + buf.readUnsignedByte(); + buf.readUnsignedByte(); + buf.readUnsignedByte(); // header + + int batteryCount = buf.readUnsignedByte(); + for (int i = 1; i <= 24; i++) { + int voltage = buf.readUnsignedShortLE(); + if (i <= batteryCount) { + position.set("battery" + i, voltage * 0.001); + } } - } - position.set(Position.KEY_CHARGE, buf.readUnsignedByte() == 0); - position.set("current", buf.readUnsignedShortLE() * 0.1); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); - position.set("batteryOverheat", buf.readUnsignedByte() > 0); - position.set("chargeProtection", buf.readUnsignedByte() > 0); - position.set("dischargeProtection", buf.readUnsignedByte() > 0); - buf.readUnsignedByte(); // drop line - buf.readUnsignedByte(); // balanced - position.set("cycles", buf.readUnsignedShortLE()); - position.set("faultAlarm", buf.readUnsignedByte()); - - buf.skipBytes(6); - - int temperatureCount = buf.readUnsignedByte(); - position.set("powerTemp", buf.readUnsignedByte() - 40); - position.set("equilibriumTemp", buf.readUnsignedByte() - 40); - for (int i = 1; i <= 7; i++) { - int temperature = buf.readUnsignedByte() - 40; - if (i <= temperatureCount) { - position.set("batteryTemp" + i, temperature); + position.set(Position.KEY_CHARGE, buf.readUnsignedByte() == 0); + position.set("current", buf.readUnsignedShortLE() * 0.1); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set("batteryOverheat", buf.readUnsignedByte() > 0); + position.set("chargeProtection", buf.readUnsignedByte() > 0); + position.set("dischargeProtection", buf.readUnsignedByte() > 0); + buf.readUnsignedByte(); // drop line + buf.readUnsignedByte(); // balanced + position.set("cycles", buf.readUnsignedShortLE()); + position.set("faultAlarm", buf.readUnsignedByte()); + + buf.skipBytes(6); + + int temperatureCount = buf.readUnsignedByte(); + position.set("powerTemp", buf.readUnsignedByte() - 40); + position.set("equilibriumTemp", buf.readUnsignedByte() - 40); + for (int i = 1; i <= 7; i++) { + int temperature = buf.readUnsignedByte() - 40; + if (i <= temperatureCount) { + position.set("batteryTemp" + i, temperature); + } } - } - position.set("calibrationCapacity", buf.readUnsignedShortLE() * 0.01); - position.set("dischargeCapacity", buf.readUnsignedIntLE()); + position.set("calibrationCapacity", buf.readUnsignedShortLE() * 0.01); + position.set("dischargeCapacity", buf.readUnsignedIntLE()); + + } else { + + String[] values = payload.split(","); + for (String value : values) { + String[] pair = value.split(":"); + int key = Integer.parseInt(pair[0], 16); + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(pair[1])); + switch (key) { + case 0x90: + position.set("cumulativeVoltage", buf.readUnsignedShortLE() * 0.1); + position.set("gatherVoltage", buf.readUnsignedShortLE() * 0.1); + position.set("current", (buf.readUnsignedShortLE() - 30000) * 0.1); + position.set("soc", buf.readUnsignedShortLE() * 0.1); + break; + case 0x91: + position.set("maxCellVoltage", buf.readUnsignedShortLE() * 0.001); + position.set("maxCellVoltageCount", buf.readUnsignedByte()); + position.set("minCellVoltage", buf.readUnsignedShortLE() * 0.001); + position.set("minCellVoltageCount", buf.readUnsignedByte()); + break; + case 0x92: + position.set("maxTemp", buf.readUnsignedByte() - 40); + position.set("maxTempCount", buf.readUnsignedByte()); + position.set("minTemp", buf.readUnsignedByte() - 40); + position.set("minTempCount", buf.readUnsignedByte()); + break; + case 0x96: + buf.readUnsignedByte(); // frame + while (buf.isReadable()) { + position.set("cellTemp" + buf.readerIndex(), buf.readUnsignedByte() - 40); + } + break; + default: + break; + } + + } + + } return position; } @@ -537,7 +580,7 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { return decodeLbsWifi(channel, remoteAddress, sentence); } else if (sentence.contains("BV00")) { return decodeVin(channel, remoteAddress, sentence); - } else if (sentence.contains("BS50")) { + } else if (sentence.contains("BS50") || sentence.contains("BS51")) { return decodeBms(channel, remoteAddress, sentence); } diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java index 1631ab051..a3b3fa86b 100644 --- a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Tk103ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tk103ProtocolDecoder(null)); + verifyAttributes(decoder, text( + "(007030201454BS5190:02150000753001DC,91:0EE8060EDC0A01DC,92:42014201DC0A01DC,93:00010127000037C8,94:0E01000002000000,95:020EE10EE20EE800030EE40EE00EE700040EDD0EE40EE400050EDC0EDF0EE400,96:0142000000000000,97:0000000000000000,98:0000000000000000)")); + verifyAttribute(decoder, text( "(352602014867BS500064FF0EF10FF10FF00FF20FF30FF20FF20FF40FF20FF40FF40FF20FF30FF20F0000000000000000000000000000000000000000000000001663000000010004000000000000000002444444420000000000A00FA000000000000000200000000315E2000000)"), "batteryTemp2", 26); -- cgit v1.2.3 From beb43ba371de5862a7ca6579daef20c8ffd83f2d Mon Sep 17 00:00:00 2001 From: Aaron Donnelly Date: Thu, 20 Apr 2023 12:06:41 +0100 Subject: Teltonika io30 addition --- src/main/java/org/traccar/model/Position.java | 3 ++- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 2bd71f383..acb1026f2 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -23,7 +23,8 @@ import org.traccar.storage.StorageName; @StorageName("tc_positions") public class Position extends Message { - + + public static final String KEY_FAULT_COUNT = "faultCount"; public static final String KEY_ORIGINAL = "raw"; public static final String KEY_INDEX = "index"; public static final String KEY_HDOP = "hdop"; diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 969b24297..7f692a30a 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -231,6 +231,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(26, null, (p, b) -> p.set("bleTemp2", b.readShort() * 0.01)); register(27, null, (p, b) -> p.set("bleTemp3", b.readShort() * 0.01)); register(28, null, (p, b) -> p.set("bleTemp4", b.readShort() * 0.01)); + register(30, fmbXXX, (p, b) -> p.set(Position.KEY_FAULT_COUNT, b.readUnsignedByte())); register(66, null, (p, b) -> p.set(Position.KEY_POWER, b.readUnsignedShort() * 0.001)); register(67, null, (p, b) -> p.set(Position.KEY_BATTERY, b.readUnsignedShort() * 0.001)); register(68, fmbXXX, (p, b) -> p.set("batteryCurrent", b.readUnsignedShort() * 0.001)); -- cgit v1.2.3 From f92bde2088001c34186eb3897cece90171a319d1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 20 Apr 2023 07:52:38 -0700 Subject: More ATrack binary parameters --- .../traccar/protocol/AtrackProtocolDecoder.java | 185 +++++++++++++++++++++ .../protocol/AtrackProtocolDecoderTest.java | 3 + 2 files changed, 188 insertions(+) diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java index 340641729..aa19e9e41 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java @@ -429,6 +429,191 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { case "MP": buf.readUnsignedByte(); // manifold absolute pressure break; + case "EO": + position.set(Position.KEY_ODOMETER, UnitsConverter.metersFromMiles(buf.readUnsignedInt())); + break; + case "EH": + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 360000); + break; + case "ZO1": + buf.readUnsignedByte(); // brake stroke status + break; + case "ZO2": + buf.readUnsignedByte(); // warning indicator status + break; + case "ZO3": + buf.readUnsignedByte(); // abs control status + break; + case "ZO4": + position.set(Position.KEY_THROTTLE, buf.readUnsignedByte() * 0.4); + break; + case "ZO5": + buf.readUnsignedByte(); // parking brake status + break; + case "ZO6": + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte() * 0.805); + break; + case "ZO7": + buf.readUnsignedByte(); // cruise control status + break; + case "ZO8": + buf.readUnsignedByte(); // accelector pedal position + break; + case "ZO9": + position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte() * 0.5); + break; + case "ZO10": + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.5); + break; + case "ZO11": + buf.readUnsignedByte(); // engine oil pressure + break; + case "ZO12": + buf.readUnsignedByte(); // boost pressure + break; + case "ZO13": + buf.readUnsignedByte(); // intake temperature + break; + case "ZO14": + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte()); + break; + case "ZO15": + buf.readUnsignedByte(); // brake application pressure + break; + case "ZO16": + buf.readUnsignedByte(); // brake primary pressure + break; + case "ZO17": + buf.readUnsignedByte(); // brake secondary pressure + break; + case "ZH1": + buf.readUnsignedShort(); // cargo weight + break; + case "ZH2": + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 16.428 / 3600); + break; + case "ZH3": + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.25); + break; + case "ZL1": + buf.readUnsignedInt(); // fuel used (natural gas) + break; + case "ZL2": + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 161); + break; + case "ZL3": + buf.readUnsignedInt(); // vehicle hours + break; + case "ZL4": + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 5 * 36000); + break; + case "ZS1": + position.set(Position.KEY_VIN, readString(buf)); + break; + case "JO1": + buf.readUnsignedByte(); // pedals + break; + case "JO2": + buf.readUnsignedByte(); // power takeoff device + break; + case "JO3": + buf.readUnsignedByte(); // accelector pedal position + break; + case "JO4": + position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte()); + break; + case "JO5": + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); + break; + case "JO6": + buf.readUnsignedByte(); // fms vehicle interface + break; + case "JO7": + buf.readUnsignedByte(); // driver 2 + break; + case "JO8": + buf.readUnsignedByte(); // driver 1 + break; + case "JO9": + buf.readUnsignedByte(); // drivers + break; + case "JO10": + buf.readUnsignedByte(); // system information + break; + case "JO11": + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); + break; + case "JO12": + buf.readUnsignedByte(); // pto engaged + break; + case "JH1": + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0); + break; + case "JH2": + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); + break; + case "JH3": + case "JH4": + case "JH5": + case "JH6": + case "JH7": + int index = Integer.parseInt(key.substring(2)) - 2; + position.set("axleWeight" + index, buf.readUnsignedShort() * 0.5); + break; + case "JH8": + position.set(Position.KEY_ODOMETER_SERVICE, buf.readUnsignedShort() * 5); + break; + case "JH9": + buf.readUnsignedShort(); // tachograph speed + break; + case "JH10": + buf.readUnsignedShort(); // ambient air temperature + break; + case "JH11": + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.05); + break; + case "JH12": + buf.readUnsignedShort(); // fuel economy + break; + case "JL1": + position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.5); + break; + case "JL2": + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 5 * 36000); + break; + case "JL3": + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); + break; + case "JL4": + position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.001); + break; + case "JS1": + position.set(Position.KEY_VIN, readString(buf)); + break; + case "JS2": + readString(buf); // fms version supported + break; + case "JS3": + position.set("driver1", readString(buf)); + break; + case "JS4": + position.set("driver2", readString(buf)); + break; + case "JN1": + buf.readUnsignedInt(); // cruise control distance + break; + case "JN2": + buf.readUnsignedInt(); // excessive idling time + break; + case "JN3": + buf.readUnsignedInt(); // excessive idling fuel + break; + case "JN4": + buf.readUnsignedInt(); // pto time + break; + case "JN5": + buf.readUnsignedInt(); // pto fuel + break; default: break; } diff --git a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java index dfdd3e579..32000c4a7 100644 --- a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -43,6 +43,9 @@ public class AtrackProtocolDecoderTest extends ProtocolTest { decoder.setCustom(true); + verifyPositions(decoder, binary( + "405099280272000300014399e3f93d136438abdf644083f56440842afb2711c701b9eaee0067020003e0bb03de0000000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000930025000000000000000000000000000000006438abdf644083f76440842afb2711c701b9eaee0067710003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000950025000000000000000000000000000000006438abdf644083f76440842afb2711c701b9eaee0067840003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000950025000000000000000000000000000000006438abdf644083f86440842afb2711c701b9eaee0067760003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c340000000000000000000000000000000000000000000095002500000000000000000000000000000000")); + verifyPositions(decoder, buffer( "@P,7A66,153,9022,863003048505515,20210207000103,20210207000103,20210207000103,103939276,1348903,97,2,5628,8,0,0,0,0,,2000,2000,\u001a,%CI%BC,3:224:F128833445E6002C09C6\r\n")); -- cgit v1.2.3 From c2637180549e69fc302f91f4685036e2697ae7bf Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 22 Apr 2023 09:11:06 -0700 Subject: Fix report scheduling --- src/main/java/org/traccar/model/Calendar.java | 13 ++++++++++--- src/main/java/org/traccar/schedule/TaskReports.java | 12 +++++------- src/test/java/org/traccar/calendar/CalendarTest.java | 15 +++++++-------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/traccar/model/Calendar.java b/src/main/java/org/traccar/model/Calendar.java index 62c51cc4a..03f1995ba 100644 --- a/src/main/java/org/traccar/model/Calendar.java +++ b/src/main/java/org/traccar/model/Calendar.java @@ -34,6 +34,7 @@ import java.time.Duration; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; @StorageName("tc_calendars") public class Calendar extends ExtendedModel { @@ -68,16 +69,22 @@ public class Calendar extends ExtendedModel { return calendar; } - public Collection findEvents(Date date) { + private Collection findEvents(Date date) { if (calendar != null) { - Period period = new Period(new DateTime(date), Duration.ZERO); - Filter filter = new Filter<>(new PeriodRule<>(period)); + var filter = new Filter(new PeriodRule<>(new Period(new DateTime(date), Duration.ZERO))); return filter.filter(calendar.getComponents(CalendarComponent.VEVENT)); } else { return List.of(); } } + public Collection findPeriods(Date date) { + var calendarDate = new net.fortuna.ical4j.model.Date(date); + return findEvents(date).stream() + .flatMap((event) -> event.getConsumedTime(calendarDate, calendarDate).stream()) + .collect(Collectors.toSet()); + } + public boolean checkMoment(Date date) { return !findEvents(date).isEmpty(); } diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index 004a6078c..176b6d537 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.java @@ -18,7 +18,7 @@ package org.traccar.schedule; import com.google.inject.Injector; import com.google.inject.servlet.RequestScoper; import com.google.inject.servlet.ServletScopes; -import net.fortuna.ical4j.model.component.VEvent; +import net.fortuna.ical4j.model.Period; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.model.BaseModel; @@ -77,16 +77,14 @@ public class TaskReports implements ScheduleTask { Calendar calendar = storage.getObject(Calendar.class, new Request( new Columns.All(), new Condition.Equals("id", report.getCalendarId()))); - var lastEvents = calendar.findEvents(lastCheck); - var currentEvents = calendar.findEvents(currentCheck); + var lastEvents = calendar.findPeriods(lastCheck); + var currentEvents = calendar.findPeriods(currentCheck); if (!lastEvents.isEmpty() && currentEvents.isEmpty()) { - VEvent event = lastEvents.iterator().next(); - Date from = event.getStartDate().getDate(); - Date to = event.getEndDate().getDate(); + Period period = lastEvents.iterator().next(); RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap()); try (RequestScoper.CloseableScope ignored = scope.open()) { - executeReport(report, from, to); + executeReport(report, period.getStart(), period.getEnd()); } } } diff --git a/src/test/java/org/traccar/calendar/CalendarTest.java b/src/test/java/org/traccar/calendar/CalendarTest.java index 6f4b30370..4106f89a9 100644 --- a/src/test/java/org/traccar/calendar/CalendarTest.java +++ b/src/test/java/org/traccar/calendar/CalendarTest.java @@ -11,6 +11,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class CalendarTest { @@ -45,14 +46,12 @@ public class CalendarTest { calendar.setData(calendarString.getBytes()); DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssX"); - Date date = format.parse("2016-12-13 22:59:59+05"); - assertTrue(!calendar.checkMoment(date)); - date = format.parse("2016-12-13 23:00:01+05"); - assertTrue(calendar.checkMoment(date)); + assertFalse(calendar.checkMoment(format.parse("2016-12-13 22:59:59+05"))); + assertTrue(calendar.checkMoment(format.parse("2016-12-13 23:00:01+05"))); + assertTrue(calendar.checkMoment(format.parse("2016-12-13 06:59:59+05"))); + assertFalse(calendar.checkMoment(format.parse("2016-12-13 07:00:01+05"))); - date = format.parse("2016-12-13 06:59:59+05"); - assertTrue(calendar.checkMoment(date)); - date = format.parse("2016-12-13 07:00:01+05"); - assertTrue(!calendar.checkMoment(date)); + var periods = calendar.findPeriods(format.parse("2016-12-13 06:59:59+05")); + assertFalse(periods.isEmpty()); } } -- cgit v1.2.3 From 30bafaed42e74863c5ca68a33c87f39d1e2de93d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 23 Apr 2023 08:29:22 -0700 Subject: Move geofenceIds to position --- schema/changelog-5.8.xml | 18 ++++++++ schema/changelog-master.xml | 1 + src/main/java/org/traccar/BasePipelineFactory.java | 2 + .../java/org/traccar/handler/GeofenceHandler.java | 52 ++++++++++++++++++++++ .../handler/events/GeofenceEventHandler.java | 41 +++++------------ .../handler/events/OverspeedEventHandler.java | 4 +- src/main/java/org/traccar/model/Device.java | 21 +-------- src/main/java/org/traccar/model/Position.java | 16 +++++++ swagger.json | 12 ++--- 9 files changed, 109 insertions(+), 58 deletions(-) create mode 100644 schema/changelog-5.8.xml create mode 100644 src/main/java/org/traccar/handler/GeofenceHandler.java diff --git a/schema/changelog-5.8.xml b/schema/changelog-5.8.xml new file mode 100644 index 000000000..ec54bf17f --- /dev/null +++ b/schema/changelog-5.8.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index 1587cc789..dd2bcc8a7 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -38,5 +38,6 @@ + diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index 38b077980..d04fed383 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -33,6 +33,7 @@ import org.traccar.handler.DistanceHandler; import org.traccar.handler.EngineHoursHandler; import org.traccar.handler.FilterHandler; import org.traccar.handler.GeocoderHandler; +import org.traccar.handler.GeofenceHandler; import org.traccar.handler.GeolocationHandler; import org.traccar.handler.HemisphereHandler; import org.traccar.handler.MotionHandler; @@ -149,6 +150,7 @@ public abstract class BasePipelineFactory extends ChannelInitializer { DistanceHandler.class, RemoteAddressHandler.class, FilterHandler.class, + GeofenceHandler.class, GeocoderHandler.class, SpeedLimitHandler.class, MotionHandler.class, diff --git a/src/main/java/org/traccar/handler/GeofenceHandler.java b/src/main/java/org/traccar/handler/GeofenceHandler.java new file mode 100644 index 000000000..fe15cef8e --- /dev/null +++ b/src/main/java/org/traccar/handler/GeofenceHandler.java @@ -0,0 +1,52 @@ +/* + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.traccar.BaseDataHandler; +import org.traccar.config.Config; +import org.traccar.helper.model.GeofenceUtil; +import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.List; + +@Singleton +@ChannelHandler.Sharable +public class GeofenceHandler extends BaseDataHandler { + + private final Config config; + private final CacheManager cacheManager; + + @Inject + public GeofenceHandler(Config config, CacheManager cacheManager) { + this.config = config; + this.cacheManager = cacheManager; + } + + @Override + protected Position handlePosition(Position position) { + + List geofenceIds = GeofenceUtil.getCurrentGeofences(config, cacheManager, position); + if (!geofenceIds.isEmpty()) { + position.setGeofenceIds(geofenceIds); + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index 9414f4b31..0ab9ca217 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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,20 +17,14 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; import org.traccar.config.Config; -import org.traccar.helper.model.GeofenceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Calendar; -import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Position; import org.traccar.session.ConnectionManager; import org.traccar.session.cache.CacheManager; import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; import javax.inject.Inject; import javax.inject.Singleton; @@ -59,36 +53,21 @@ public class GeofenceEventHandler extends BaseEventHandler { @Override protected Map analyzePosition(Position position) { - Device device = cacheManager.getObject(Device.class, position.getDeviceId()); - if (device == null) { - return null; - } - if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) { + if (!PositionUtil.isLatest(cacheManager, position)) { return null; } - List currentGeofences = GeofenceUtil.getCurrentGeofences(config, cacheManager, position); List oldGeofences = new ArrayList<>(); - if (device.getGeofenceIds() != null) { - oldGeofences.addAll(device.getGeofenceIds()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); + if (lastPosition != null && lastPosition.getGeofenceIds() != null) { + oldGeofences.addAll(lastPosition.getGeofenceIds()); } - List newGeofences = new ArrayList<>(currentGeofences); - newGeofences.removeAll(oldGeofences); - oldGeofences.removeAll(currentGeofences); - - - if (!oldGeofences.isEmpty() || !newGeofences.isEmpty()) { - device.setGeofenceIds(currentGeofences.isEmpty() ? null : currentGeofences); - - try { - storage.updateObject(device, new Request( - new Columns.Include("geofenceIds"), - new Condition.Equals("id", device.getId()))); - } catch (StorageException e) { - throw new RuntimeException("Update device geofences error", e); - } - connectionManager.updateDevice(true, device); + List newGeofences = new ArrayList<>(); + if (position.getGeofenceIds() != null) { + newGeofences.addAll(position.getGeofenceIds()); + newGeofences.removeAll(oldGeofences); + oldGeofences.removeAll(position.getGeofenceIds()); } Map events = new HashMap<>(); diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 4d6aa8857..40f1c7442 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -84,8 +84,8 @@ public class OverspeedEventHandler extends BaseEventHandler { double geofenceSpeedLimit = 0; long overspeedGeofenceId = 0; - if (device.getGeofenceIds() != null) { - for (long geofenceId : device.getGeofenceIds()) { + if (position.getGeofenceIds() != null) { + for (long geofenceId : position.getGeofenceIds()) { Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId); if (geofence != null) { double currentSpeedLimit = geofence.getDouble(Keys.EVENT_OVERSPEED_LIMIT.getKey()); diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index b8c87921d..b7cffac49 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -15,14 +15,12 @@ */ package org.traccar.model; -import java.util.Date; -import java.util.List; -import java.util.stream.Collectors; - import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.storage.QueryIgnore; import org.traccar.storage.StorageName; +import java.util.Date; + @StorageName("tc_devices") public class Device extends GroupedModel implements Disableable { @@ -83,21 +81,6 @@ public class Device extends GroupedModel implements Disableable { this.positionId = positionId; } - private List geofenceIds; - - @QueryIgnore - public List getGeofenceIds() { - return geofenceIds; - } - - public void setGeofenceIds(List geofenceIds) { - if (geofenceIds != null) { - this.geofenceIds = geofenceIds.stream().map(Number::longValue).collect(Collectors.toList()); - } else { - this.geofenceIds = null; - } - } - private String phone; public String getPhone() { diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 2bd71f383..3ed340703 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -16,6 +16,8 @@ package org.traccar.model; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.storage.QueryIgnore; @@ -309,6 +311,20 @@ public class Position extends Message { this.network = network; } + private List geofenceIds; + + public List getGeofenceIds() { + return geofenceIds; + } + + public void setGeofenceIds(List geofenceIds) { + if (geofenceIds != null) { + this.geofenceIds = geofenceIds.stream().map(Number::longValue).collect(Collectors.toList()); + } else { + this.geofenceIds = null; + } + } + @JsonIgnore @QueryIgnore @Override diff --git a/swagger.json b/swagger.json index dde673e19..3d3842b67 100644 --- a/swagger.json +++ b/swagger.json @@ -2725,6 +2725,12 @@ "type": "object", "properties": {} }, + "geofenceIds": { + "type": "array", + "items": { + "type": "integer" + } + }, "attributes": { "type": "object", "properties": {} @@ -2927,12 +2933,6 @@ "category": { "type": "string" }, - "geofenceIds": { - "type": "array", - "items": { - "type": "integer" - } - }, "attributes": { "type": "object", "properties": {} -- cgit v1.2.3 From 2b3c1be84310e2c7c6a3dff4ec37be2560af772e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 24 Apr 2023 16:12:02 -0700 Subject: Fix report config issue --- src/main/java/org/traccar/reports/common/ReportUtils.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index f1a2f7d54..0c168e4ef 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -51,7 +51,6 @@ import org.traccar.storage.query.Request; import javax.annotation.Nullable; import javax.inject.Inject; -import javax.inject.Singleton; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -63,7 +62,6 @@ import java.util.Date; import java.util.List; import java.util.Locale; -@Singleton public class ReportUtils { private final Config config; -- cgit v1.2.3 From 03cebd3191a9c27c4b38e585b323d5c8d6868571 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 29 Apr 2023 13:56:51 -0700 Subject: Add outdated position filter --- src/main/java/org/traccar/config/Keys.java | 8 ++++++++ src/main/java/org/traccar/handler/FilterHandler.java | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 8ced32153..c69289403 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1238,6 +1238,14 @@ public final class Keys { "filter.duplicate", List.of(KeyType.CONFIG)); + /** + * Filter messages that do not have GPS location. If they are not filtered, they will include the last known + * location. + */ + public static final ConfigKey FILTER_OUTDATED = new BooleanConfigKey( + "filter.outdated", + List.of(KeyType.CONFIG)); + /** * Filter records with fix time in the future. The value is specified in seconds. Records that have fix time more * than the specified number of seconds later than current server time would be filtered out. diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 1d1c27b7a..9ff94deb0 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -48,6 +48,7 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { private final boolean filterInvalid; private final boolean filterZero; private final boolean filterDuplicate; + private final boolean filterOutdated; private final long filterFuture; private final long filterPast; private final boolean filterApproximate; @@ -69,6 +70,7 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { filterInvalid = config.getBoolean(Keys.FILTER_INVALID); filterZero = config.getBoolean(Keys.FILTER_ZERO); filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE); + filterOutdated = config.getBoolean(Keys.FILTER_OUTDATED); filterFuture = config.getLong(Keys.FILTER_FUTURE) * 1000; filterPast = config.getLong(Keys.FILTER_PAST) * 1000; filterAccuracy = config.getInteger(Keys.FILTER_ACCURACY); @@ -115,6 +117,10 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { return false; } + private boolean filterOutdated(Position position) { + return filterOutdated && position.getOutdated(); + } + private boolean filterFuture(Position position) { return filterFuture != 0 && position.getFixTime().getTime() > System.currentTimeMillis() + filterFuture; } @@ -189,6 +195,9 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { if (filterZero(position)) { filterType.append("Zero "); } + if (filterOutdated(position)) { + filterType.append("Outdated "); + } if (filterFuture(position)) { filterType.append("Future "); } -- cgit v1.2.3 From 0f8dd92a6b1b9a288be888838a30195a6de41250 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 29 Apr 2023 14:20:38 -0700 Subject: Add X3 status sync --- .../org/traccar/protocol/Gt06ProtocolDecoder.java | 23 ++++++++++++++++++++++ .../traccar/protocol/Gt06ProtocolDecoderTest.java | 5 ++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 02a629103..7013533bc 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -1028,6 +1028,29 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.01); return position; + } else if (subType == 0x04) { + + CharSequence content = buf.readCharSequence(buf.readableBytes() - 4 - 2, StandardCharsets.US_ASCII); + String[] values = content.toString().split(";"); + for (String value : values) { + String[] pair = value.split("="); + switch (pair[0]) { + case "ALM1": + case "ALM2": + case "ALM3": + position.set("alarm" + pair[0].charAt(3) + "Status", Integer.parseInt(pair[1], 16)); + case "STA1": + position.set("otherStatus", Integer.parseInt(pair[1], 16)); + break; + case "DYD": + position.set("engineStatus", Integer.parseInt(pair[1], 16)); + break; + default: + break; + } + } + return position; + } else if (subType == 0x05) { if (buf.readableBytes() >= 6 + 1 + 6) { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 5dc6b803e..8f2c97f86 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,9 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttributes(decoder, binary( + "797900849404414c4d313d43353b414c4d323d43433b414c4d333d35433b535441313d43303b4459443d30313b534f533d303133323838333730302c2c3b43454e5445523d303133323838333730303b46454e43453d46656e63652c4f46462c302c302e3030303030302c302e3030303030302c3330302c494e206f72204f55542c313b00b79d120d0a")); + verifyAttribute(decoder, binary( "78782912170316053b3bcf015b51220af1201105d56100000000000000000000869c0130010000000238d1af0d0a"), Position.KEY_DRIVING_TIME, 0); @@ -190,7 +193,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyAttributes(decoder, binary( "79790008940000ed0289d6860d0a")); - verifyNull(decoder, binary( + verifyAttributes(decoder, binary( "797900a59404414c4d313d34353b414c4d323d44353b414c4d333d35353b535441313d34303b4459443d30313b534f533d303538353036313536372c2c3b43454e5445523d3b46454e43453d46656e63652c4f46462c302c302e3030303030302c302e3030303030302c3330302c494e206f72204f55542c303b49434349443d38393937313033313031303038393539303432463b4d4f44453d4d4f44452c312c3138303b0008f65e0d0a")); verifyPosition(decoder, binary( -- cgit v1.2.3 From bb6964f03867d039a547c103cd16390f78688022 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 30 Apr 2023 11:49:28 -0700 Subject: Fix group commands (fix #5075) --- src/main/java/org/traccar/api/resource/CommandResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index b69d4d9ac..3df2244d1 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -124,7 +124,7 @@ public class CommandResource extends ExtendedObjectResource { for (Device device : devices) { Command command = QueuedCommand.fromCommand(entity).toCommand(); command.setDeviceId(device.getId()); - result = result && commandsManager.sendCommand(command); + result = commandsManager.sendCommand(command) && result; } } else { permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); -- cgit v1.2.3 From e73f36db83b9dc00a5dfe0a9625f40bd2698c3fa Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 3 May 2023 13:59:35 -0700 Subject: Decode Escort fuel sensor --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index c7713bdc2..0135e78b7 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -978,7 +978,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { index += 1; // device type if (BitUtil.check(mask, 0)) { - index += 1; // digital fuel sensor data + position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(data[index++], 16)); } if (BitUtil.check(mask, 1)) { diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 515c14921..4b0edfd81 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+BUFF:GTERI,410502,864802030794634,,00000001,,10,1,1,0.0,0,3027.8,-78.706612,-0.955699,20230418170736,0740,0002,A08C,2AB72D,00,0.0,,,,100,110000,1,0099,20230418171004,8B98$"), + Position.KEY_FUEL_LEVEL, 153); + verifyPositions(decoder, false, buffer( "+BUFF:GTFRI,2E0503,861106050005423,,,0,1,,,,,,,,,,,,0,0,,98,1,0,,,20200101000001,0083$")); -- cgit v1.2.3 From 3dad196b882c031e4ed36536c3b2deeb1b3bbff6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 4 May 2023 16:07:52 -0700 Subject: Extend HS-5000G OBD support --- src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java | 5 +++++ src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 2d952c759..2fb7c6e92 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -236,6 +236,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { while (buf.readableBytes() > 4) { int subtype = buf.readUnsignedShort(); int length = buf.readUnsignedShort() - 4; + int endIndex = buf.readerIndex() + length; switch (subtype) { case 0x0001: int coolantTemperature = buf.readUnsignedByte() - 40; @@ -253,6 +254,9 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); buf.readUnsignedInt(); // trip id + if (buf.readerIndex() < endIndex) { + position.set("adBlueLevel", buf.readUnsignedByte() * 0.4); + } break; case 0x0005: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); @@ -295,6 +299,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(length); break; } + buf.readerIndex(endIndex); } if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java index ee6c3fa7f..fe4b077c6 100644 --- a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java @@ -20,6 +20,9 @@ public class HuaShengProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "c000000077aa0200000000000e000100143347315f48312e315f56312e30372e54000300133335353835353035303434303635380004000b3531323030303000050005010006000400070004000800050000090018383936313032353431343533333239313833360d000a000f796573696e7465726e6574c0")); + verifyNotNull(decoder, binary( + "c0000000b9aa00000000000013c800001132333035303431343537323600186bc30045e5b8002a008b0077002d000100187f0c4b2600d906ec000005938800000000000e0000040009110000000e0005000a1d0400000079000900154646464646464646464646464646464646000f00133836323230353035353339313733360010000c302e30303030303000110008000000000014000bf81b204901b52a001500060000002000153231394030324030403130343438393139c0")); + verifyAttribute(decoder, binary( "C00000001CAA120000000000020001001001000200030043008200C100C0"), Position.KEY_DTCS, "P0100 P0200 P0300 C0300 B0200 U0100"); -- cgit v1.2.3 From 445366d9a49fbee7a28a41e1f95423c07b54b725 Mon Sep 17 00:00:00 2001 From: K-J-Dod24 Date: Fri, 5 May 2023 14:29:50 +0100 Subject: io32 to coolant correcting io115 to engine temp --- src/main/java/org/traccar/model/Position.java | 1 + src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 3ed340703..c48e34e03 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -81,6 +81,7 @@ public class Position extends Message { public static final String KEY_ACCELERATION = "acceleration"; public static final String KEY_DEVICE_TEMP = "deviceTemp"; // celsius public static final String KEY_COOLANT_TEMP = "coolantTemp"; // celsius + public static final String KEY_ENGINE_TEMP = "engineTemp"; // celsius public static final String KEY_ENGINE_LOAD = "engineLoad"; public static final String KEY_OPERATOR = "operator"; public static final String KEY_COMMAND = "command"; diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 969b24297..3cb89d6f7 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -231,6 +231,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(26, null, (p, b) -> p.set("bleTemp2", b.readShort() * 0.01)); register(27, null, (p, b) -> p.set("bleTemp3", b.readShort() * 0.01)); register(28, null, (p, b) -> p.set("bleTemp4", b.readShort() * 0.01)); + register(32, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readByte())); register(66, null, (p, b) -> p.set(Position.KEY_POWER, b.readUnsignedShort() * 0.001)); register(67, null, (p, b) -> p.set(Position.KEY_BATTERY, b.readUnsignedShort() * 0.001)); register(68, fmbXXX, (p, b) -> p.set("batteryCurrent", b.readUnsignedShort() * 0.001)); @@ -246,7 +247,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { }); register(80, fmbXXX, (p, b) -> p.set("dataMode", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); - register(115, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readShort() * 0.1)); + register(115, fmbXXX, (p, b) -> p.set(Position.KEY_ENGINE_TEMP, b.readShort() * 0.1)); 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)); -- cgit v1.2.3 From 1e992e5f83cf97b13803098edec64d68f1843e91 Mon Sep 17 00:00:00 2001 From: Kieran Dodson <128472473+K-J-Dod24@users.noreply.github.com> Date: Tue, 9 May 2023 10:18:42 +0100 Subject: Revert "Teltonika io30 fault count" --- src/main/java/org/traccar/model/Position.java | 3 +-- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index be995ca2a..3ed340703 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -25,8 +25,7 @@ import org.traccar.storage.StorageName; @StorageName("tc_positions") public class Position extends Message { - - public static final String KEY_FAULT_COUNT = "faultCount"; + public static final String KEY_ORIGINAL = "raw"; public static final String KEY_INDEX = "index"; public static final String KEY_HDOP = "hdop"; diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 7f692a30a..969b24297 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -231,7 +231,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(26, null, (p, b) -> p.set("bleTemp2", b.readShort() * 0.01)); register(27, null, (p, b) -> p.set("bleTemp3", b.readShort() * 0.01)); register(28, null, (p, b) -> p.set("bleTemp4", b.readShort() * 0.01)); - register(30, fmbXXX, (p, b) -> p.set(Position.KEY_FAULT_COUNT, b.readUnsignedByte())); register(66, null, (p, b) -> p.set(Position.KEY_POWER, b.readUnsignedShort() * 0.001)); register(67, null, (p, b) -> p.set(Position.KEY_BATTERY, b.readUnsignedShort() * 0.001)); register(68, fmbXXX, (p, b) -> p.set("batteryCurrent", b.readUnsignedShort() * 0.001)); -- cgit v1.2.3 From 7b935f715761120a4149e6aaced7641314c53c47 Mon Sep 17 00:00:00 2001 From: K-J-Dod24 Date: Tue, 9 May 2023 14:01:44 +0100 Subject: io30 teltonika fault count --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 969b24297..fc18424df 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -231,6 +231,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(26, null, (p, b) -> p.set("bleTemp2", b.readShort() * 0.01)); register(27, null, (p, b) -> p.set("bleTemp3", b.readShort() * 0.01)); register(28, null, (p, b) -> p.set("bleTemp4", b.readShort() * 0.01)); + register(30, fmbXXX, (p, b) -> p.set("faultCount", b.readUnsignedByte())); register(66, null, (p, b) -> p.set(Position.KEY_POWER, b.readUnsignedShort() * 0.001)); register(67, null, (p, b) -> p.set(Position.KEY_BATTERY, b.readUnsignedShort() * 0.001)); register(68, fmbXXX, (p, b) -> p.set("batteryCurrent", b.readUnsignedShort() * 0.001)); -- cgit v1.2.3 From 680fe003a7cc9da354a989936d8f7f07580110bb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 9 May 2023 07:35:17 -0700 Subject: Add Flespi event code --- src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java index a7f6c284a..95d491af7 100644 --- a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java @@ -130,6 +130,9 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { case "dout": position.set(Position.KEY_OUTPUT, ((JsonNumber) value).intValue()); return true; + case "report.reason": + position.set(Position.KEY_EVENT, ((JsonNumber) value).intValue()); + return true; case "gps.vehicle.mileage": position.set(Position.KEY_ODOMETER, ((JsonNumber) value).doubleValue()); return true; -- cgit v1.2.3 From 1e8c232e37d0f041a8518cb4790322965bdd6fd5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 9 May 2023 07:51:41 -0700 Subject: Handle missing geofences --- .../handler/events/GeofenceEventHandler.java | 27 ++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index 0ab9ca217..096f71373 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -16,15 +16,12 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; -import org.traccar.config.Config; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Calendar; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Position; -import org.traccar.session.ConnectionManager; import org.traccar.session.cache.CacheManager; -import org.traccar.storage.Storage; import javax.inject.Inject; import javax.inject.Singleton; @@ -37,18 +34,11 @@ import java.util.Map; @ChannelHandler.Sharable public class GeofenceEventHandler extends BaseEventHandler { - private final Config config; private final CacheManager cacheManager; - private final ConnectionManager connectionManager; - private final Storage storage; @Inject - public GeofenceEventHandler( - Config config, CacheManager cacheManager, ConnectionManager connectionManager, Storage storage) { - this.config = config; + public GeofenceEventHandler(CacheManager cacheManager) { this.cacheManager = cacheManager; - this.connectionManager = connectionManager; - this.storage = storage; } @Override @@ -72,12 +62,15 @@ public class GeofenceEventHandler extends BaseEventHandler { Map events = new HashMap<>(); for (long geofenceId : oldGeofences) { - long calendarId = cacheManager.getObject(Geofence.class, geofenceId).getCalendarId(); - Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null; - if (calendar == null || calendar.checkMoment(position.getFixTime())) { - Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position); - event.setGeofenceId(geofenceId); - events.put(event, position); + Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId); + if (geofence != null) { + long calendarId = geofence.getCalendarId(); + Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null; + if (calendar == null || calendar.checkMoment(position.getFixTime())) { + Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position); + event.setGeofenceId(geofenceId); + events.put(event, position); + } } } for (long geofenceId : newGeofences) { -- cgit v1.2.3 From e2402983eb53f6cd384cdd09cc0d217772023b9a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 9 May 2023 08:16:00 -0700 Subject: Expand transparent data --- .../traccar/protocol/HuabaoProtocolDecoder.java | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 1aebba4e6..f0b7cf6ca 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -877,6 +877,22 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x0539: position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01); break; + case 0x052D: + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); + break; + case 0x0530: + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); + break; + case 0x0535: + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1); + break; + case 0x0536: + position.set(Position.KEY_RPM, buf.readUnsignedShort()); + break; + case 0x0547: + case 0x0548: + position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); + break; default: switch (length) { case 1: @@ -898,6 +914,17 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { decodeCoordinates(position, buf); position.setTime(time); break; + case 0x02: + count = buf.readUnsignedByte(); + for (int i = 0; i < count; i++) { + buf.readUnsignedInt(); // system id + int codeCount = buf.readUnsignedShort(); + for (int j = 0; j < codeCount; j++) { + buf.skipBytes(16); // code + } + } + decodeCoordinates(position, buf); + break; case 0x03: count = buf.readUnsignedByte(); for (int i = 0; i < count; i++) { -- cgit v1.2.3 From 4c57f717f678969a46d9d84538a3116018dce9c1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 9 May 2023 08:19:24 -0700 Subject: Use last location info --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index f0b7cf6ca..fcbb55043 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -911,8 +911,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { break; } } + getLastLocation(position, time); decodeCoordinates(position, buf); - position.setTime(time); break; case 0x02: count = buf.readUnsignedByte(); @@ -923,6 +923,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(16); // code } } + getLastLocation(position, time); decodeCoordinates(position, buf); break; case 0x03: @@ -953,8 +954,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } buf.skipBytes(length); } + getLastLocation(position, time); decodeCoordinates(position, buf); - position.setTime(time); break; case 0x0B: if (buf.readUnsignedByte() > 0) { -- cgit v1.2.3 From d797671b2ce6fb70ac868bb96f87be8b2a85e4f9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 9 May 2023 08:23:16 -0700 Subject: Fix unit tests --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index fcbb55043..05e2fb8cc 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -913,6 +913,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } getLastLocation(position, time); decodeCoordinates(position, buf); + position.setTime(time); break; case 0x02: count = buf.readUnsignedByte(); @@ -925,6 +926,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } getLastLocation(position, time); decodeCoordinates(position, buf); + position.setTime(time); break; case 0x03: count = buf.readUnsignedByte(); @@ -956,6 +958,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } getLastLocation(position, time); decodeCoordinates(position, buf); + position.setTime(time); break; case 0x0B: if (buf.readUnsignedByte() > 0) { -- cgit v1.2.3 From ae1205dfdded530e4cdf7bb665fe52cf197c33be Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 10 May 2023 07:33:05 -0700 Subject: Fix Huabao event decoding --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 8 ++++---- src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 05e2fb8cc..ed71861a5 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -333,10 +333,6 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // power level position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); break; - case 0x60: - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - buf.skipBytes(length - 2); - break; case 0x61: position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); break; @@ -488,6 +484,10 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01); } break; + case 0x60: + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + buf.skipBytes(length - 2); + break; case 0x80: buf.readUnsignedByte(); // content endIndex = buf.writerIndex() - 2; diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 67f214563..32c632353 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyAttribute(decoder, binary( + "7e02000071768060874297002d0000000000208022015a30b006c869f8000000000000230505062034600b0004003930303235343939660b01cc0000000c40f89f27b067083133323134333232690201936a01116b01006c0f34363030383138353937303632343071143839383630343938313032313930353835373430607e"), + Position.KEY_EVENT, 4); + verifyAttribute(decoder, binary( "7e0200002f017028775424038d000000000000000a0189dbeb04ca653a00000012014723040700074401040000000030011b31010ee1012dea020001dc7e"), Position.KEY_BATTERY_LEVEL, 45); -- cgit v1.2.3 From 46f09ad36017e9ac160cf029551dc2586f21504f Mon Sep 17 00:00:00 2001 From: Zeus The Developer <75146431+zeustd@users.noreply.github.com> Date: Wed, 10 May 2023 20:24:42 +0530 Subject: Add VL502 Alarms Added support for VL502 additional alarms, Protocol document Page 44, 0x03 --- .../java/org/traccar/protocol/HuabaoProtocolDecoder.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index ed71861a5..2c6f9af96 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -951,6 +951,21 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x23: position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING); break; + case 0x26: + case 0x27: + case 0x28: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + case 0x31: + case 0x32: + position.set(Position.KEY_ALARM, Position.ALARM_DOOR); + break; + case 0x01: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); + break; + case 0x02: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; default: break; } -- cgit v1.2.3 From c3fe534d28c35d252ca97d99ae1b4d1fbe87d2f0 Mon Sep 17 00:00:00 2001 From: Zeus The Developer <75146431+zeustd@users.noreply.github.com> Date: Wed, 10 May 2023 20:34:54 +0530 Subject: Update case by order id Sort cases by order id --- .../java/org/traccar/protocol/HuabaoProtocolDecoder.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 2c6f9af96..e6980dc28 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -934,6 +934,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int id = buf.readUnsignedByte(); int length = buf.readUnsignedByte(); switch (id) { + case 0x01: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); + break; + case 0x02: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; case 0x1A: position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); break; @@ -960,12 +966,6 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x32: position.set(Position.KEY_ALARM, Position.ALARM_DOOR); break; - case 0x01: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); - break; - case 0x02: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; default: break; } -- cgit v1.2.3 From 22c86a7096743ef592facd36f1ddcc756eb0459b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 11 May 2023 07:51:47 -0700 Subject: Increase iStartek frame limit --- src/main/java/org/traccar/protocol/StartekProtocol.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/StartekProtocol.java b/src/main/java/org/traccar/protocol/StartekProtocol.java index d010df858..1b1c93e33 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocol.java +++ b/src/main/java/org/traccar/protocol/StartekProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 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. @@ -38,7 +38,7 @@ public class StartekProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new LineBasedFrameDecoder(1100)); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StartekProtocolEncoder(StartekProtocol.this)); -- cgit v1.2.3 From 78e18b3da86de2e2c5f2aa67ff03c3827708d6a0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 13 May 2023 12:55:28 -0700 Subject: Add missing user field --- swagger.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/swagger.json b/swagger.json index 3d3842b67..889728d33 100644 --- a/swagger.json +++ b/swagger.json @@ -2799,6 +2799,9 @@ "limitCommands": { "type": "boolean" }, + "fixedEmail": { + "type": "boolean" + }, "poiLayer": { "type": "string" }, -- cgit v1.2.3 From f68d23d79d0321ef47f72fff2388b5f4aac1beff Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 May 2023 10:28:44 -0700 Subject: Per device motion threshold --- src/main/java/org/traccar/config/Keys.java | 2 +- src/main/java/org/traccar/handler/MotionHandler.java | 16 ++++++++++------ .../java/org/traccar/reports/common/TripsConfig.java | 12 ++---------- src/test/java/org/traccar/handler/MotionHandlerTest.java | 16 ++++++++++++---- .../traccar/handler/events/MotionEventHandlerTest.java | 6 +++--- src/test/java/org/traccar/reports/ReportUtilsTest.java | 16 ++++++++-------- 6 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index c69289403..f0e0bf2b6 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -380,7 +380,7 @@ public final class Keys { */ public static final ConfigKey EVENT_MOTION_SPEED_THRESHOLD = new DoubleConfigKey( "event.motion.speedThreshold", - List.of(KeyType.CONFIG), + List.of(KeyType.CONFIG, KeyType.DEVICE), 0.01); /** diff --git a/src/main/java/org/traccar/handler/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java index 10312f9b3..297527b4d 100644 --- a/src/main/java/org/traccar/handler/MotionHandler.java +++ b/src/main/java/org/traccar/handler/MotionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +18,10 @@ package org.traccar.handler; import io.netty.channel.ChannelHandler; import org.traccar.BaseDataHandler; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; -import org.traccar.reports.common.TripsConfig; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; import javax.inject.Singleton; @@ -28,17 +30,19 @@ import javax.inject.Singleton; @ChannelHandler.Sharable public class MotionHandler extends BaseDataHandler { - private final double speedThreshold; + private final CacheManager cacheManager; @Inject - public MotionHandler(TripsConfig tripsConfig) { - speedThreshold = tripsConfig.getSpeedThreshold(); + public MotionHandler(CacheManager cacheManager) { + this.cacheManager = cacheManager; } @Override protected Position handlePosition(Position position) { if (!position.hasAttribute(Position.KEY_MOTION)) { - position.set(Position.KEY_MOTION, position.getSpeed() > speedThreshold); + double threshold = AttributeUtil.lookup( + cacheManager, Keys.EVENT_MOTION_SPEED_THRESHOLD, position.getDeviceId()); + position.set(Position.KEY_MOTION, position.getSpeed() > threshold); } return position; } diff --git a/src/main/java/org/traccar/reports/common/TripsConfig.java b/src/main/java/org/traccar/reports/common/TripsConfig.java index 52db97b74..841d9c652 100644 --- a/src/main/java/org/traccar/reports/common/TripsConfig.java +++ b/src/main/java/org/traccar/reports/common/TripsConfig.java @@ -33,20 +33,18 @@ public class TripsConfig { config.getLong(Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION) * 1000, config.getLong(Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION) * 1000, config.getBoolean(Keys.REPORT_TRIP_USE_IGNITION), - config.getBoolean(Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS), - config.getDouble(Keys.EVENT_MOTION_SPEED_THRESHOLD)); + config.getBoolean(Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS)); } public TripsConfig( double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration, - long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions, double speedThreshold) { + long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions) { this.minimalTripDistance = minimalTripDistance; this.minimalTripDuration = minimalTripDuration; this.minimalParkingDuration = minimalParkingDuration; this.minimalNoDataDuration = minimalNoDataDuration; this.useIgnition = useIgnition; this.processInvalidPositions = processInvalidPositions; - this.speedThreshold = speedThreshold; } private final double minimalTripDistance; @@ -85,10 +83,4 @@ public class TripsConfig { return processInvalidPositions; } - private final double speedThreshold; - - public double getSpeedThreshold() { - return speedThreshold; - } - } diff --git a/src/test/java/org/traccar/handler/MotionHandlerTest.java b/src/test/java/org/traccar/handler/MotionHandlerTest.java index 2a7af23ba..10cdf6a90 100644 --- a/src/test/java/org/traccar/handler/MotionHandlerTest.java +++ b/src/test/java/org/traccar/handler/MotionHandlerTest.java @@ -1,10 +1,15 @@ package org.traccar.handler; import org.junit.jupiter.api.Test; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Device; import org.traccar.model.Position; -import org.traccar.reports.common.TripsConfig; +import org.traccar.session.cache.CacheManager; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -13,10 +18,13 @@ public class MotionHandlerTest { @Test public void testCalculateMotion() { - TripsConfig tripsConfig = mock(TripsConfig.class); - when(tripsConfig.getSpeedThreshold()).thenReturn(0.01); + var cacheManager = mock(CacheManager.class); + when(cacheManager.getObject(eq(Device.class), anyLong())).thenReturn(mock(Device.class)); + var config = mock(Config.class); + when(config.getString(Keys.EVENT_MOTION_SPEED_THRESHOLD.getKey())).thenReturn("0.01"); + when(cacheManager.getConfig()).thenReturn(config); - MotionHandler motionHandler = new MotionHandler(tripsConfig); + MotionHandler motionHandler = new MotionHandler(cacheManager); Position position = motionHandler.handlePosition(new Position()); diff --git a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java index f2d858656..2be3f4647 100644 --- a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java @@ -36,7 +36,7 @@ public class MotionEventHandlerTest extends BaseTest { @Test public void testMotionWithPosition() throws ParseException { - TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false, false); MotionState state = new MotionState(); @@ -63,7 +63,7 @@ public class MotionEventHandlerTest extends BaseTest { @Test public void testMotionFluctuation() throws ParseException { - TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false, false); MotionState state = new MotionState(); @@ -94,7 +94,7 @@ public class MotionEventHandlerTest extends BaseTest { @Test public void testStopWithPositionIgnition() throws ParseException { - TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, true, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, true, false); MotionState state = new MotionState(); state.setMotionStreak(true); diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index 09e5b3e27..e116f24b4 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -101,7 +101,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:15:00.000", 0, 3000), position("2016-01-01 00:25:00.000", 0, 3000)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); @@ -156,7 +156,7 @@ public class ReportUtilsTest extends BaseTest { data.get(5).set(Position.KEY_IGNITION, false); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, true, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, true, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); @@ -227,7 +227,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:19:00.000", 0, 7000), position("2016-01-01 00:29:00.000", 0, 7000)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); @@ -278,7 +278,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:04:00.000", 1, 0), position("2016-01-01 00:05:00.000", 0, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); @@ -307,7 +307,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:04:00.000", 1, 0), position("2016-01-01 00:05:00.000", 2, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); @@ -336,7 +336,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:22:00.000", 0, 0), position("2016-01-01 00:32:00.000", 0, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); @@ -365,7 +365,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:04:00.000", 5, 0), position("2016-01-01 00:05:00.000", 5, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); @@ -390,7 +390,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:24:00.000", 5, 800), position("2016-01-01 00:25:00.000", 5, 900)); - TripsConfig tripsConfig = new TripsConfig(500, 200000, 200000, 900000, false, false, 0.01); + TripsConfig tripsConfig = new TripsConfig(500, 200000, 200000, 900000, false, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), tripsConfig, mock(VelocityEngine.class), null); -- cgit v1.2.3 From a96a75cc268f2819431b7441090052b01bf61bed Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 May 2023 14:07:50 -0700 Subject: Per device trip config --- src/main/java/org/traccar/config/Keys.java | 12 +-- .../traccar/handler/events/MotionEventHandler.java | 14 +-- .../org/traccar/helper/model/AttributeUtil.java | 106 +++++++++++++++++++-- .../org/traccar/reports/common/ReportUtils.java | 7 +- .../org/traccar/reports/common/TripsConfig.java | 31 ++---- .../handler/events/MotionEventHandlerTest.java | 6 +- .../java/org/traccar/reports/ReportUtilsTest.java | 86 +++++++++-------- 7 files changed, 176 insertions(+), 86 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index f0e0bf2b6..432182fdd 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -373,7 +373,7 @@ public final class Keys { */ public static final ConfigKey EVENT_MOTION_PROCESS_INVALID_POSITIONS = new BooleanConfigKey( "event.motion.processInvalidPositions", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG, KeyType.DEVICE)); /** * If the speed is above specified value, the object is considered to be in motion. Default value is 0.01 knots. @@ -1167,7 +1167,7 @@ public final class Keys { */ public static final ConfigKey REPORT_TRIP_MINIMAL_TRIP_DISTANCE = new LongConfigKey( "report.trip.minimalTripDistance", - List.of(KeyType.CONFIG), + List.of(KeyType.CONFIG, KeyType.DEVICE), 500L); /** @@ -1175,7 +1175,7 @@ public final class Keys { */ public static final ConfigKey REPORT_TRIP_MINIMAL_TRIP_DURATION = new LongConfigKey( "report.trip.minimalTripDuration", - List.of(KeyType.CONFIG), + List.of(KeyType.CONFIG, KeyType.DEVICE), 300L); /** @@ -1183,7 +1183,7 @@ public final class Keys { */ public static final ConfigKey REPORT_TRIP_MINIMAL_PARKING_DURATION = new LongConfigKey( "report.trip.minimalParkingDuration", - List.of(KeyType.CONFIG), + List.of(KeyType.CONFIG, KeyType.DEVICE), 300L); /** @@ -1191,7 +1191,7 @@ public final class Keys { */ public static final ConfigKey REPORT_TRIP_MINIMAL_NO_DATA_DURATION = new LongConfigKey( "report.trip.minimalNoDataDuration", - List.of(KeyType.CONFIG), + List.of(KeyType.CONFIG, KeyType.DEVICE), 3600L); /** @@ -1199,7 +1199,7 @@ public final class Keys { */ public static final ConfigKey REPORT_TRIP_USE_IGNITION = new BooleanConfigKey( "report.trip.useIgnition", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG, KeyType.DEVICE)); /** * Ignore odometer value reported by the device and use server-calculated total distance instead. This is useful diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index c406bd935..63b512291 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,8 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Event; @@ -46,14 +48,12 @@ public class MotionEventHandler extends BaseEventHandler { private final CacheManager cacheManager; private final Storage storage; - private final TripsConfig tripsConfig; @Inject public MotionEventHandler( CacheManager cacheManager, Storage storage, TripsConfig tripsConfig) { this.cacheManager = cacheManager; this.storage = storage; - this.tripsConfig = tripsConfig; } @Override @@ -61,14 +61,16 @@ public class MotionEventHandler extends BaseEventHandler { long deviceId = position.getDeviceId(); Device device = cacheManager.getObject(Device.class, deviceId); - if (device == null) { + if (device == null || !PositionUtil.isLatest(cacheManager, position)) { return null; } - if (!PositionUtil.isLatest(cacheManager, position) - || !tripsConfig.getProcessInvalidPositions() && !position.getValid()) { + boolean processInvalid = AttributeUtil.lookup( + cacheManager, Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS, deviceId); + if (!processInvalid && !position.getValid()) { return null; } + TripsConfig tripsConfig = new TripsConfig(new AttributeUtil.CacheProvider(cacheManager, deviceId)); MotionState state = MotionState.fromDevice(device); MotionProcessor.updateState(state, position, position.getBoolean(Position.KEY_MOTION), tripsConfig); if (state.isChanged()) { diff --git a/src/main/java/org/traccar/helper/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java index 43558e8f7..2630f64f0 100644 --- a/src/main/java/org/traccar/helper/model/AttributeUtil.java +++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -15,25 +15,44 @@ */ package org.traccar.helper.model; +import org.traccar.api.security.PermissionsService; +import org.traccar.config.Config; import org.traccar.config.ConfigKey; import org.traccar.config.KeyType; import org.traccar.config.Keys; import org.traccar.model.Device; import org.traccar.model.Group; +import org.traccar.model.Server; import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; public final class AttributeUtil { private AttributeUtil() { } - @SuppressWarnings({ "deprecation", "unchecked" }) + public interface Provider { + Device getDevice(); + Group getGroup(long groupId); + Server getServer(); + Config getConfig(); + } + public static T lookup(CacheManager cacheManager, ConfigKey key, long deviceId) { - Device device = cacheManager.getObject(Device.class, deviceId); + return lookup(new CacheProvider(cacheManager, deviceId), key); + } + + @SuppressWarnings({ "deprecation", "unchecked" }) + public static T lookup(Provider provider, ConfigKey key) { + Device device = provider.getDevice(); Object result = device.getAttributes().get(key.getKey()); long groupId = device.getGroupId(); while (result == null && groupId > 0) { - Group group = cacheManager.getObject(Group.class, groupId); + Group group = provider.getGroup(groupId); if (group != null) { result = group.getAttributes().get(key.getKey()); groupId = group.getGroupId(); @@ -42,10 +61,10 @@ public final class AttributeUtil { } } if (result == null && key.hasType(KeyType.SERVER)) { - result = cacheManager.getServer().getAttributes().get(key.getKey()); + result = provider.getServer().getAttributes().get(key.getKey()); } if (result == null && key.hasType(KeyType.CONFIG)) { - result = cacheManager.getConfig().getString(key.getKey()); + result = provider.getConfig().getString(key.getKey()); } if (result != null) { @@ -91,4 +110,79 @@ public final class AttributeUtil { return defaultPassword; } + public static class CacheProvider implements Provider { + + private final CacheManager cacheManager; + private final long deviceId; + + public CacheProvider(CacheManager cacheManager, long deviceId) { + this.cacheManager = cacheManager; + this.deviceId = deviceId; + } + + @Override + public Device getDevice() { + return cacheManager.getObject(Device.class, deviceId); + } + + @Override + public Group getGroup(long groupId) { + return cacheManager.getObject(Group.class, groupId); + } + + @Override + public Server getServer() { + return cacheManager.getServer(); + } + + @Override + public Config getConfig() { + return cacheManager.getConfig(); + } + } + + public static class StorageProvider implements Provider { + + private final Config config; + private final Storage storage; + private final PermissionsService permissionsService; + private final Device device; + + public StorageProvider(Config config, Storage storage, PermissionsService permissionsService, Device device) { + this.config = config; + this.storage = storage; + this.permissionsService = permissionsService; + this.device = device; + } + + @Override + public Device getDevice() { + return device; + } + + @Override + public Group getGroup(long groupId) { + try { + return storage.getObject( + Group.class, new Request(new Columns.All(), new Condition.Equals("id", groupId))); + } catch (StorageException e) { + throw new RuntimeException(e); + } + } + + @Override + public Server getServer() { + try { + return permissionsService.getServer(); + } catch (StorageException e) { + throw new RuntimeException(e); + } + } + + @Override + public Config getConfig() { + return config; + } + } + } diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 0c168e4ef..f5aa6d040 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -31,6 +31,7 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.geocoder.Geocoder; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.AttributeUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.helper.model.UserUtil; import org.traccar.model.BaseModel; @@ -67,18 +68,16 @@ public class ReportUtils { private final Config config; private final Storage storage; private final PermissionsService permissionsService; - private final TripsConfig tripsConfig; private final VelocityEngine velocityEngine; private final Geocoder geocoder; @Inject public ReportUtils( Config config, Storage storage, PermissionsService permissionsService, - TripsConfig tripsConfig, VelocityEngine velocityEngine, @Nullable Geocoder geocoder) { + VelocityEngine velocityEngine, @Nullable Geocoder geocoder) { this.config = config; this.storage = storage; this.permissionsService = permissionsService; - this.tripsConfig = tripsConfig; this.velocityEngine = velocityEngine; this.geocoder = geocoder; } @@ -306,6 +305,8 @@ public class ReportUtils { Class reportClass) throws StorageException { Collection result = new ArrayList<>(); + TripsConfig tripsConfig = new TripsConfig( + new AttributeUtil.StorageProvider(config, storage, permissionsService, device)); ArrayList positions = new ArrayList<>(positionCollection); if (!positions.isEmpty()) { diff --git a/src/main/java/org/traccar/reports/common/TripsConfig.java b/src/main/java/org/traccar/reports/common/TripsConfig.java index 841d9c652..2792114d4 100644 --- a/src/main/java/org/traccar/reports/common/TripsConfig.java +++ b/src/main/java/org/traccar/reports/common/TripsConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,35 +16,28 @@ */ package org.traccar.reports.common; -import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; -import javax.inject.Inject; -import javax.inject.Singleton; - -@Singleton public class TripsConfig { - @Inject - public TripsConfig(Config config) { + public TripsConfig(AttributeUtil.Provider attributeProvider) { this( - config.getLong(Keys.REPORT_TRIP_MINIMAL_TRIP_DISTANCE), - config.getLong(Keys.REPORT_TRIP_MINIMAL_TRIP_DURATION) * 1000, - config.getLong(Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION) * 1000, - config.getLong(Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION) * 1000, - config.getBoolean(Keys.REPORT_TRIP_USE_IGNITION), - config.getBoolean(Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS)); + AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_TRIP_DISTANCE), + AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_TRIP_DURATION) * 1000, + AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION) * 1000, + AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION) * 1000, + AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_USE_IGNITION)); } public TripsConfig( double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration, - long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions) { + long minimalNoDataDuration, boolean useIgnition) { this.minimalTripDistance = minimalTripDistance; this.minimalTripDuration = minimalTripDuration; this.minimalParkingDuration = minimalParkingDuration; this.minimalNoDataDuration = minimalNoDataDuration; this.useIgnition = useIgnition; - this.processInvalidPositions = processInvalidPositions; } private final double minimalTripDistance; @@ -77,10 +70,4 @@ public class TripsConfig { return useIgnition; } - private final boolean processInvalidPositions; - - public boolean getProcessInvalidPositions() { - return processInvalidPositions; - } - } diff --git a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java index 2be3f4647..c61ae913d 100644 --- a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java @@ -36,7 +36,7 @@ public class MotionEventHandlerTest extends BaseTest { @Test public void testMotionWithPosition() throws ParseException { - TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false, false); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false); MotionState state = new MotionState(); @@ -63,7 +63,7 @@ public class MotionEventHandlerTest extends BaseTest { @Test public void testMotionFluctuation() throws ParseException { - TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false, false); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false); MotionState state = new MotionState(); @@ -94,7 +94,7 @@ public class MotionEventHandlerTest extends BaseTest { @Test public void testStopWithPositionIgnition() throws ParseException { - TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, true, false); + TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, true); MotionState state = new MotionState(); state.setMotionStreak(true); diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index e116f24b4..22d70c93a 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -2,15 +2,16 @@ package org.traccar.reports; import org.apache.velocity.app.VelocityEngine; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.api.security.PermissionsService; import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.reports.common.ReportUtils; -import org.traccar.reports.common.TripsConfig; import org.traccar.reports.model.StopReportItem; import org.traccar.reports.model.TripReportItem; import org.traccar.storage.Storage; @@ -24,6 +25,7 @@ import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.TimeZone; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -62,6 +64,19 @@ public class ReportUtilsTest extends BaseTest { return position; } + + private Device mockDevice( + double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration, + long minimalNoDataDuration, boolean useIgnition) { + Device device = mock(Device.class); + when(device.getAttributes()).thenReturn(Map.of( + Keys.REPORT_TRIP_MINIMAL_TRIP_DISTANCE.getKey(), minimalTripDistance, + Keys.REPORT_TRIP_MINIMAL_TRIP_DURATION.getKey(), minimalTripDuration, + Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION.getKey(), minimalParkingDuration, + Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION.getKey(), minimalNoDataDuration, + Keys.REPORT_TRIP_USE_IGNITION.getKey(), useIgnition)); + return device; + } @Test public void testCalculateDistance() { @@ -78,8 +93,7 @@ public class ReportUtilsTest extends BaseTest { @Test public void testCalculateSpentFuel() { ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - mock(TripsConfig.class), mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); Position startPosition = new Position(); Position endPosition = new Position(); assertEquals(reportUtils.calculateFuel(startPosition, endPosition), 0.0, 0.01); @@ -101,12 +115,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:15:00.000", 0, 3000), position("2016-01-01 00:25:00.000", 0, 3000)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false); + Device device = mockDevice(500, 300, 180, 900, false); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(mock(Device.class), data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -120,7 +133,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -156,12 +169,11 @@ public class ReportUtilsTest extends BaseTest { data.get(5).set(Position.KEY_IGNITION, false); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, true, false); + Device device = mockDevice(500, 300, 180, 900, true); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -175,7 +187,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - trips = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, TripReportItem.class); + trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -189,7 +201,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -227,12 +239,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:19:00.000", 0, 7000), position("2016-01-01 00:29:00.000", 0, 7000)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false); + Device device = mockDevice(500, 300, 180, 900, false); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -246,7 +257,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(7000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -278,12 +289,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:04:00.000", 1, 0), position("2016-01-01 00:05:00.000", 0, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); + Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -307,12 +317,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:04:00.000", 1, 0), position("2016-01-01 00:05:00.000", 2, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); + Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -336,12 +345,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:22:00.000", 0, 0), position("2016-01-01 00:32:00.000", 0, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); + Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -365,12 +373,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:04:00.000", 5, 0), position("2016-01-01 00:05:00.000", 5, 0)); - TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false); + Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(result); assertTrue(result.isEmpty()); @@ -390,12 +397,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:24:00.000", 5, 800), position("2016-01-01 00:25:00.000", 5, 900)); - TripsConfig tripsConfig = new TripsConfig(500, 200000, 200000, 900000, false, false); + Device device = mockDevice(500, 200, 200, 900, false); ReportUtils reportUtils = new ReportUtils( - mock(Config.class), storage, mock(PermissionsService.class), - tripsConfig, mock(VelocityEngine.class), null); + mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -409,7 +415,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(7, itemTrip.getMaxSpeed(), 0.01); assertEquals(600, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); -- cgit v1.2.3 From 454abd506ac6e1865ece67b534805253e7e63337 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 May 2023 14:08:44 -0700 Subject: Fix injection issue --- src/main/java/org/traccar/handler/events/MotionEventHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index 63b512291..d2c54ccf3 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -50,8 +50,7 @@ public class MotionEventHandler extends BaseEventHandler { private final Storage storage; @Inject - public MotionEventHandler( - CacheManager cacheManager, Storage storage, TripsConfig tripsConfig) { + public MotionEventHandler(CacheManager cacheManager, Storage storage) { this.cacheManager = cacheManager; this.storage = storage; } -- cgit v1.2.3 From b9b2c5c111a56acfab6ac6b5c314f6f0dcb9baec Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 May 2023 14:14:23 -0700 Subject: Fix default boolean values --- src/main/java/org/traccar/config/Keys.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 432182fdd..162a3fe13 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -373,7 +373,8 @@ public final class Keys { */ public static final ConfigKey EVENT_MOTION_PROCESS_INVALID_POSITIONS = new BooleanConfigKey( "event.motion.processInvalidPositions", - List.of(KeyType.CONFIG, KeyType.DEVICE)); + List.of(KeyType.CONFIG, KeyType.DEVICE), + false); /** * If the speed is above specified value, the object is considered to be in motion. Default value is 0.01 knots. @@ -1199,7 +1200,8 @@ public final class Keys { */ public static final ConfigKey REPORT_TRIP_USE_IGNITION = new BooleanConfigKey( "report.trip.useIgnition", - List.of(KeyType.CONFIG, KeyType.DEVICE)); + List.of(KeyType.CONFIG, KeyType.DEVICE), + false); /** * Ignore odometer value reported by the device and use server-calculated total distance instead. This is useful @@ -1207,7 +1209,8 @@ public final class Keys { */ public static final ConfigKey REPORT_IGNORE_ODOMETER = new BooleanConfigKey( "report.ignoreOdometer", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + false); /** * Boolean flag to enable or disable position filtering. -- cgit v1.2.3 From 553527d9fbe689be243acbf219bed432f15c25e3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 May 2023 07:40:15 -0700 Subject: Decode HHDLink power --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 3 +++ src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index e6980dc28..4beee7696 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -488,6 +488,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_EVENT, buf.readUnsignedShort()); buf.skipBytes(length - 2); break; + case 0x69: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + break; case 0x80: buf.readUnsignedByte(); // content endIndex = buf.writerIndex() - 2; diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 32c632353..2f317d049 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyAttribute(decoder, binary( + "7e0200006476806111898300710000000000100046005d3156065f7128000000000000230511165956660b01fe000001031a5d1a8101670831333231343332326902018b6a01166b01006c0f323034303830393230373533363735711438393434343738383030303030323131303030464b7e"), + Position.KEY_BATTERY, 3.95); + verifyAttribute(decoder, binary( "7e02000071768060874297002d0000000000208022015a30b006c869f8000000000000230505062034600b0004003930303235343939660b01cc0000000c40f89f27b067083133323134333232690201936a01116b01006c0f34363030383138353937303632343071143839383630343938313032313930353835373430607e"), Position.KEY_EVENT, 4); -- cgit v1.2.3 From 6dae98179630a15c5f62899b32ed093e293822e2 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Mon, 15 May 2023 19:42:22 +0300 Subject: Add [Protocol]TranSyncProtocol Add TranSyncProtocol.java Add TranSyncProtocolDecoder.java Add TranSyncProtocolDecoderTest.java --- .../org/traccar/protocol/TranSyncProtocol.java | 22 ++ .../traccar/protocol/TranSyncProtocolDecoder.java | 353 +++++++++++++++++++++ .../protocol/TranSyncProtocolDecoderTest.java | 22 ++ 3 files changed, 397 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/TranSyncProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java new file mode 100644 index 000000000..0634642df --- /dev/null +++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import javax.inject.Inject; + +public class TranSyncProtocol extends BaseProtocol { + + @Inject + public TranSyncProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new TranSyncProtocolDecoder(TranSyncProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java new file mode 100644 index 000000000..7cafc09ee --- /dev/null +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -0,0 +1,353 @@ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class TranSyncProtocolDecoder extends BaseProtocolDecoder { + + public TranSyncProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private boolean isOptionalParameters; + private boolean extended; + private final String STX = "3A3A"; + private final String ETX = "2323"; + private String lac; + private String deviceId; + private Date datePacket; + private double latitude; + private double longitude; + private double speed; + private int course; + private int mobileNetworkCode; + private int gsmSignalStrength; + private double batteryVoltage; + private int satellitesNumber; + private int hdopProtocol; + private short adcVoltageInMilliVolts; + private String rfidTagName; + private int adc2; + private int cellIdInt; + private int lacInt; + private int odometer; + private boolean isGpsFix; + private boolean isLiveData; + private boolean hasGpsAlert; + private boolean isIgnitionOff; + private boolean isPowerOff; + private int deviceAlert; + private String gpsTrackerModel; + private boolean isOutPutTwo; + private boolean isOutPutOne; + private boolean isInPutThree; + + + + public String getLac() { + return lac; + } + + public void setLac(String lac) { + this.lac = lac; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public void setDatePacket(Date datePacket) { + this.datePacket = datePacket; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public int getCourse() { + return course; + } + + public void setCourse(int course) { + this.course = course; + } + + public void setCellId(String cellId) { + } + + public int getAdc2() { + return adc2; + } + + public void setAdc2(String adc2) { + this.adc2 = Integer.parseInt(adc2); + } + + public double getSpeed() { + return speed; + } + + public void setSpeed(double speed) { + this.speed = speed; + } + + public void setTimestampPacket(int year, int month, int day, int hours, int minutes, int seconds) { + + String dataString = ""+year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds; + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); + simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + try { + Date deviceTime = simpleDateFormat.parse(dataString); + long timestampPacket = deviceTime.toInstant().toEpochMilli(); + this.setDatePacket(deviceTime); + + } catch (ParseException e) { + e.printStackTrace(); + } + } + + protected void setDeviceAlert(Position position, int alert) { + switch (alert) { + case 10: + position.set(Position.ALARM_SOS, true); + break; + case 11: + position.set(Position.ALARM_SOS, false); + break; + case 16: + position.set(Position.KEY_EVENT, 16); + break; + case 3: + position.set("distressCutOff", true); + break; + case 22: + position.set("tilt", true); + break; + case 9: + position.set(Position.KEY_EVENT, 9); + case 17: + position.set(Position.ALARM_OVERSPEED, true); + break; + case 13: + position.set(Position.ALARM_BRAKING, true); + break; + case 14: + position.set(Position.ALARM_ACCELERATION, true); + break; + case 15: + position.set(Position.KEY_EVENT, 15); + break; + case 23: + position.set(Position.ALARM_ACCIDENT, true); + break; + case 12: + position.set(Position.KEY_EVENT, 12); + break; + case 6: + position.set(Position.ALARM_POWER_RESTORED, true); + break; + case 4: + position.set(Position.ALARM_LOW_BATTERY, true); + break; + case 5: + position.set(Position.KEY_EVENT, 5); + break; + + } + + } + + protected void setInstanceParameters(Object msg) throws Exception { + ByteBuf buf = (ByteBuf) msg; + + if (ByteBufUtil.hexDump(buf, 0, 2).toUpperCase().equals(this.STX)) { + buf.readUnsignedShort(); + } + int packetLength = buf.readByte(); + this.lacInt = buf.readUnsignedShort(); + this.deviceId = ByteBufUtil.hexDump(buf, buf.readerIndex(), 8).toUpperCase().trim().replaceFirst("^0+(?!$)", ""); + buf.readBytes(8); + int informationSerialNumber = buf.readUnsignedShort(); + int protocolNumber = buf.readUnsignedByte(); + // Information Content + int year = buf.readUnsignedByte(); + int month = buf.readUnsignedByte(); + int day = buf.readUnsignedByte(); + int hour = buf.readUnsignedByte(); + int minute = buf.readUnsignedByte(); + int second = buf.readUnsignedByte(); + this.setTimestampPacket(year, month, day, hour, minute, second); + this.latitude = (long) buf.readUnsignedInt() / 1800000.0; + this.longitude = (long) buf.readUnsignedInt() / 1800000.0; + this.speed = UnitsConverter.knotsFromKph(buf.readUnsignedByte()); + this.course = buf.readUnsignedShort(); + this.mobileNetworkCode = buf.readUnsignedByte(); + this.cellIdInt = buf.readUnsignedShort(); + // Status Bytes + int zeroByte = buf.readUnsignedByte(); + this.isOutPutTwo = BitUtil.check(zeroByte, 0); + this.isOutPutOne = BitUtil.check(zeroByte, 1); + this.isInPutThree = BitUtil.check(zeroByte, 2); + this.isPowerOff = BitUtil.check(zeroByte, 3); + this.isIgnitionOff = BitUtil.check(zeroByte, 4); + boolean isgpsFixed = BitUtil.check(zeroByte, 7); + + + this.isGpsFix = BitUtil.check(zeroByte, 0); + int oneByte = buf.readUnsignedByte(); + this.deviceAlert = buf.readUnsignedByte(); + int threeByte = buf.readUnsignedByte(); + this.isLiveData = (threeByte & 0b10000000) == 0; + this.hasGpsAlert = (threeByte & 0b00100000) != 0; + int trackerType = threeByte & 0b00001111; + + switch (trackerType) { + case 1: + this.gpsTrackerModel = "basic"; + break; + case 2: + this.gpsTrackerModel = "asset"; + break; + case 3: + this.gpsTrackerModel = "bike"; + break; + case 4: + this.gpsTrackerModel = "serial"; + break; + case 5: + this.gpsTrackerModel = "obd"; + break; + case 6: + this.gpsTrackerModel = "l1"; + break; + case 7: + this.gpsTrackerModel = "ais"; + break; + default: + this.gpsTrackerModel = "unknown"; + break; + } + // Additional Info + this.gsmSignalStrength = buf.readUnsignedByte(); + this.batteryVoltage = (double) (buf.readUnsignedByte() / 10); + this.satellitesNumber = buf.readUnsignedByte(); + this.hdopProtocol = buf.readUnsignedByte(); + this.adcVoltageInMilliVolts = (short) buf.readUnsignedShort(); + this.isOptionalParameters = (boolean) (buf.readableBytes() > 2); + // Optional parameters + if (this.isOptionalParameters) { // Always True + int odometerIndex = buf.readUnsignedByte(); + int odometerLength = buf.readUnsignedByte(); + if (odometerLength > 0) { + String odometerReading = ByteBufUtil.hexDump(buf, buf.readerIndex(), odometerLength).toUpperCase().trim().replaceFirst("^0+(?!$)", ""); + this.odometer = Integer.parseInt(odometerReading); + buf.readBytes(odometerLength); + } + if ((buf.readableBytes() > 2)) { + int rfidIndex = buf.readUnsignedByte(); + int rfidLength = buf.readUnsignedByte(); + if(rfidLength > 0) { + this.rfidTagName = ByteBufUtil.hexDump(buf, buf.readerIndex(), rfidLength).toUpperCase().trim(); + buf.readBytes(rfidLength); + } + } + if ((buf.readableBytes() > 5)) { + int adcTwoIndex = buf.readUnsignedByte(); + int adcTwoLength = buf.readUnsignedByte(); + if (adcTwoLength > 0){ + this.adc2 = buf.readUnsignedShort(); + } + } + } + + } + + private Position positionHandler(Channel channel, SocketAddress remoteAddress) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, this.deviceId); + if (deviceSession == null) { + return null; + } + Position position = new Position(getProtocolName()); + long devicesessionId = deviceSession.getDeviceId(); + position.setDeviceId(devicesessionId) ; + position.setValid(true); + position.setTime(this.datePacket); + position.setLatitude(this.latitude); + position.setLongitude(this.longitude); + position.setSpeed(this.speed); + position.setCourse(this.course); + position.set("model", this.gpsTrackerModel); + position.set(Position.KEY_HDOP, this.hdopProtocol); + position.set(Position.KEY_BATTERY, this.batteryVoltage); + position.set(Position.KEY_ODOMETER, this.odometer); + position.set(Position.PREFIX_ADC + 1, this.adcVoltageInMilliVolts); + position.set(Position.PREFIX_ADC + 2, this.adc2); + position.set("tag", this.rfidTagName); + position.set(Position.KEY_SATELLITES, this.satellitesNumber); + CellTower cellTower = CellTower.fromLacCid(getConfig(), this.lacInt, this.cellIdInt); + cellTower.setMobileNetworkCode(this.mobileNetworkCode); + cellTower.setSignalStrength(this.gsmSignalStrength); + position.setNetwork(new Network(cellTower)); + if (this.isOutPutOne){ position.set(Position.PREFIX_OUT + 1, this.isOutPutOne);} + if (this.isOutPutTwo){ position.set(Position.PREFIX_OUT + 2, this.isOutPutTwo);} + if (this.isInPutThree){ position.set(Position.PREFIX_IN + 2, this.isInPutThree);} + if (this.isGpsFix) { position.set("gpsFix", this.isGpsFix); } + if (!this.isLiveData) { position.set("restored", true); } + if (this.hasGpsAlert) { + position.set(Position.ALARM_GPS_ANTENNA_CUT, true); + position.set("gpsAlert", true); + } + position.set(Position.KEY_IGNITION, this.isIgnitionOff); + if (isPowerOff){ position.set(Position.ALARM_POWER_OFF, this.isPowerOff );} + position.set(Position.KEY_GPS, true); + if (this.deviceAlert > 0) { setDeviceAlert(position, this.deviceAlert); } + + return position; + } + + @Override + protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + try { + setInstanceParameters(msg); + } + catch (Exception e) { + return null; + } + + return positionHandler(channel, remoteAddress); + } + +} diff --git a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java new file mode 100644 index 000000000..1b90566d4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class TranSyncProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new TranSyncProtocolDecoder(null)); + + + verifyPosition(decoder, binary( + "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323")); + + verifyAttributes(decoder, binary( + "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323") + ); + } +} -- cgit v1.2.3 From cd092d7e2733881266a3b864743df61e6ac76ce4 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Mon, 15 May 2023 21:55:20 +0300 Subject: Remove Instance variables from TranSyncProtocolDecoder.java Add parseDate function Add getTrackerModel function Add setNetwork function Rename setTimestampPacket function -> getDatefromIntegerParameters --- .../traccar/protocol/TranSyncProtocolDecoder.java | 303 ++++++--------------- 1 file changed, 84 insertions(+), 219 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index 7cafc09ee..d5a69dbe2 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -24,117 +24,18 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - private boolean isOptionalParameters; - private boolean extended; - private final String STX = "3A3A"; - private final String ETX = "2323"; - private String lac; - private String deviceId; - private Date datePacket; - private double latitude; - private double longitude; - private double speed; - private int course; - private int mobileNetworkCode; - private int gsmSignalStrength; - private double batteryVoltage; - private int satellitesNumber; - private int hdopProtocol; - private short adcVoltageInMilliVolts; - private String rfidTagName; - private int adc2; - private int cellIdInt; - private int lacInt; - private int odometer; - private boolean isGpsFix; - private boolean isLiveData; - private boolean hasGpsAlert; - private boolean isIgnitionOff; - private boolean isPowerOff; - private int deviceAlert; - private String gpsTrackerModel; - private boolean isOutPutTwo; - private boolean isOutPutOne; - private boolean isInPutThree; - - - - public String getLac() { - return lac; - } - - public void setLac(String lac) { - this.lac = lac; - } - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public void setDatePacket(Date datePacket) { - this.datePacket = datePacket; - } - - public double getLatitude() { - return latitude; - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } - - public double getLongitude() { - return longitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - public int getCourse() { - return course; - } - - public void setCourse(int course) { - this.course = course; - } - - public void setCellId(String cellId) { - } - - public int getAdc2() { - return adc2; - } - - public void setAdc2(String adc2) { - this.adc2 = Integer.parseInt(adc2); - } - - public double getSpeed() { - return speed; - } - - public void setSpeed(double speed) { - this.speed = speed; - } - - public void setTimestampPacket(int year, int month, int day, int hours, int minutes, int seconds) { + public Date getDatefromIntegerParameters(int year, int month, int day, int hours, int minutes, int seconds) { String dataString = ""+year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); try { - Date deviceTime = simpleDateFormat.parse(dataString); - long timestampPacket = deviceTime.toInstant().toEpochMilli(); - this.setDatePacket(deviceTime); + return simpleDateFormat.parse(dataString); } catch (ParseException e) { e.printStackTrace(); } + return null; } protected void setDeviceAlert(Position position, int alert) { @@ -188,166 +89,130 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } - protected void setInstanceParameters(Object msg) throws Exception { - ByteBuf buf = (ByteBuf) msg; + private void setNetwork(Position position, int lacInt, int cellIdInt, int mobileNetworkCode, int gsmSignalStrength){ + CellTower cellTower = CellTower.fromLacCid(getConfig(), lacInt, cellIdInt); + cellTower.setMobileNetworkCode(mobileNetworkCode); + cellTower.setSignalStrength(gsmSignalStrength); + position.setNetwork(new Network(cellTower)); + + } + + private String getTrackerModel(int mask){ + + switch (mask) { + case 1: + return "basic"; + case 2: + return "asset"; + case 3: + return "bike"; + + case 4: + return "serial"; + + case 5: + return "obd"; + case 6: + return "l1"; + case 7: + return "ais"; + default: + return "unknown"; + } + + } - if (ByteBufUtil.hexDump(buf, 0, 2).toUpperCase().equals(this.STX)) { + private Position parseData(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + if (ByteBufUtil.hexDump(buf, 0, 2).equalsIgnoreCase("3A3A")) { buf.readUnsignedShort(); } int packetLength = buf.readByte(); - this.lacInt = buf.readUnsignedShort(); - this.deviceId = ByteBufUtil.hexDump(buf, buf.readerIndex(), 8).toUpperCase().trim().replaceFirst("^0+(?!$)", ""); + int lacInt = buf.readUnsignedShort(); + String deviceId = ByteBufUtil.hexDump(buf, buf.readerIndex(), 8).toUpperCase().trim().replaceFirst("^0+(?!$)", ""); buf.readBytes(8); int informationSerialNumber = buf.readUnsignedShort(); int protocolNumber = buf.readUnsignedByte(); - // Information Content + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + long devicesessionId = deviceSession.getDeviceId(); + + position.setDeviceId(devicesessionId) ; + position.setValid(true); int year = buf.readUnsignedByte(); int month = buf.readUnsignedByte(); int day = buf.readUnsignedByte(); int hour = buf.readUnsignedByte(); int minute = buf.readUnsignedByte(); int second = buf.readUnsignedByte(); - this.setTimestampPacket(year, month, day, hour, minute, second); - this.latitude = (long) buf.readUnsignedInt() / 1800000.0; - this.longitude = (long) buf.readUnsignedInt() / 1800000.0; - this.speed = UnitsConverter.knotsFromKph(buf.readUnsignedByte()); - this.course = buf.readUnsignedShort(); - this.mobileNetworkCode = buf.readUnsignedByte(); - this.cellIdInt = buf.readUnsignedShort(); - // Status Bytes + position.setTime(getDatefromIntegerParameters(year, month, day, hour, minute, second)); + position.setLatitude(buf.readUnsignedInt() / 1800000.0); + position.setLongitude(buf.readUnsignedInt() / 1800000.0); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedShort()); + int mobileNetworkCode = buf.readUnsignedByte(); + int cellIdInt = buf.readUnsignedShort(); int zeroByte = buf.readUnsignedByte(); - this.isOutPutTwo = BitUtil.check(zeroByte, 0); - this.isOutPutOne = BitUtil.check(zeroByte, 1); - this.isInPutThree = BitUtil.check(zeroByte, 2); - this.isPowerOff = BitUtil.check(zeroByte, 3); - this.isIgnitionOff = BitUtil.check(zeroByte, 4); - boolean isgpsFixed = BitUtil.check(zeroByte, 7); - - - this.isGpsFix = BitUtil.check(zeroByte, 0); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(zeroByte, 0)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(zeroByte, 1)); + position.set(Position.PREFIX_IN + 3, BitUtil.check(zeroByte, 2)); + if (BitUtil.check(zeroByte, 3)) position.set(Position.ALARM_POWER_OFF, true); + position.set(Position.KEY_IGNITION, BitUtil.check(zeroByte, 4)); + position.set("gpsFix", BitUtil.check(zeroByte, 7)); int oneByte = buf.readUnsignedByte(); - this.deviceAlert = buf.readUnsignedByte(); + int deviceAlert = buf.readUnsignedByte(); + if (deviceAlert > 0) { setDeviceAlert(position, deviceAlert); } int threeByte = buf.readUnsignedByte(); - this.isLiveData = (threeByte & 0b10000000) == 0; - this.hasGpsAlert = (threeByte & 0b00100000) != 0; - int trackerType = threeByte & 0b00001111; - - switch (trackerType) { - case 1: - this.gpsTrackerModel = "basic"; - break; - case 2: - this.gpsTrackerModel = "asset"; - break; - case 3: - this.gpsTrackerModel = "bike"; - break; - case 4: - this.gpsTrackerModel = "serial"; - break; - case 5: - this.gpsTrackerModel = "obd"; - break; - case 6: - this.gpsTrackerModel = "l1"; - break; - case 7: - this.gpsTrackerModel = "ais"; - break; - default: - this.gpsTrackerModel = "unknown"; - break; + if (!((threeByte & 0b10000000) == 0)) position.set("restored", true); + if ((threeByte & 0b00100000) != 0) { + position.set(Position.ALARM_GPS_ANTENNA_CUT, true); + position.set("gpsAlert", true); } - // Additional Info - this.gsmSignalStrength = buf.readUnsignedByte(); - this.batteryVoltage = (double) (buf.readUnsignedByte() / 10); - this.satellitesNumber = buf.readUnsignedByte(); - this.hdopProtocol = buf.readUnsignedByte(); - this.adcVoltageInMilliVolts = (short) buf.readUnsignedShort(); - this.isOptionalParameters = (boolean) (buf.readableBytes() > 2); - // Optional parameters - if (this.isOptionalParameters) { // Always True + position.set("model", getTrackerModel(threeByte & 0b00001111)); + int gsmSignalStrength = buf.readUnsignedByte(); + position.set(Position.KEY_BATTERY, (double) (buf.readUnsignedByte() / 10)); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_HDOP, buf.readUnsignedByte()); + position.set(Position.PREFIX_ADC + 1, (short) buf.readUnsignedShort()); + boolean isOptionalParameters = (buf.readableBytes() > 2); + setNetwork(position, lacInt, cellIdInt, mobileNetworkCode, gsmSignalStrength); + if (isOptionalParameters) { // Always True int odometerIndex = buf.readUnsignedByte(); int odometerLength = buf.readUnsignedByte(); if (odometerLength > 0) { String odometerReading = ByteBufUtil.hexDump(buf, buf.readerIndex(), odometerLength).toUpperCase().trim().replaceFirst("^0+(?!$)", ""); - this.odometer = Integer.parseInt(odometerReading); + int odometer = Integer.parseInt(odometerReading); buf.readBytes(odometerLength); + position.set(Position.KEY_ODOMETER, odometer); } if ((buf.readableBytes() > 2)) { int rfidIndex = buf.readUnsignedByte(); int rfidLength = buf.readUnsignedByte(); if(rfidLength > 0) { - this.rfidTagName = ByteBufUtil.hexDump(buf, buf.readerIndex(), rfidLength).toUpperCase().trim(); + String rfidTagName = ByteBufUtil.hexDump(buf, buf.readerIndex(), rfidLength).toUpperCase().trim(); buf.readBytes(rfidLength); + position.set("tag", rfidTagName); } } if ((buf.readableBytes() > 5)) { int adcTwoIndex = buf.readUnsignedByte(); int adcTwoLength = buf.readUnsignedByte(); if (adcTwoLength > 0){ - this.adc2 = buf.readUnsignedShort(); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); } } } - } - - private Position positionHandler(Channel channel, SocketAddress remoteAddress) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, this.deviceId); - if (deviceSession == null) { - return null; - } - Position position = new Position(getProtocolName()); - long devicesessionId = deviceSession.getDeviceId(); - position.setDeviceId(devicesessionId) ; - position.setValid(true); - position.setTime(this.datePacket); - position.setLatitude(this.latitude); - position.setLongitude(this.longitude); - position.setSpeed(this.speed); - position.setCourse(this.course); - position.set("model", this.gpsTrackerModel); - position.set(Position.KEY_HDOP, this.hdopProtocol); - position.set(Position.KEY_BATTERY, this.batteryVoltage); - position.set(Position.KEY_ODOMETER, this.odometer); - position.set(Position.PREFIX_ADC + 1, this.adcVoltageInMilliVolts); - position.set(Position.PREFIX_ADC + 2, this.adc2); - position.set("tag", this.rfidTagName); - position.set(Position.KEY_SATELLITES, this.satellitesNumber); - CellTower cellTower = CellTower.fromLacCid(getConfig(), this.lacInt, this.cellIdInt); - cellTower.setMobileNetworkCode(this.mobileNetworkCode); - cellTower.setSignalStrength(this.gsmSignalStrength); - position.setNetwork(new Network(cellTower)); - if (this.isOutPutOne){ position.set(Position.PREFIX_OUT + 1, this.isOutPutOne);} - if (this.isOutPutTwo){ position.set(Position.PREFIX_OUT + 2, this.isOutPutTwo);} - if (this.isInPutThree){ position.set(Position.PREFIX_IN + 2, this.isInPutThree);} - if (this.isGpsFix) { position.set("gpsFix", this.isGpsFix); } - if (!this.isLiveData) { position.set("restored", true); } - if (this.hasGpsAlert) { - position.set(Position.ALARM_GPS_ANTENNA_CUT, true); - position.set("gpsAlert", true); - } - position.set(Position.KEY_IGNITION, this.isIgnitionOff); - if (isPowerOff){ position.set(Position.ALARM_POWER_OFF, this.isPowerOff );} - position.set(Position.KEY_GPS, true); - if (this.deviceAlert > 0) { setDeviceAlert(position, this.deviceAlert); } - return position; } @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - try { - setInstanceParameters(msg); - } - catch (Exception e) { - return null; - } - - return positionHandler(channel, remoteAddress); + ByteBuf buffer = (ByteBuf) msg; + return parseData(channel, remoteAddress, buffer); } } -- cgit v1.2.3 From e44e9f860b11a50b3e39e3895ea9ea5624282b78 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 May 2023 12:06:14 -0700 Subject: Add HTML branding overrides --- src/main/java/org/traccar/api/MediaFilter.java | 11 +-- src/main/java/org/traccar/model/ExtendedModel.java | 8 ++- .../java/org/traccar/web/CharResponseWrapper.java | 82 ++++++++++++++++++++++ src/main/java/org/traccar/web/OverrideFilter.java | 71 +++++++++++++++++++ src/main/java/org/traccar/web/WebModule.java | 4 +- 5 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/traccar/web/CharResponseWrapper.java create mode 100644 src/main/java/org/traccar/web/OverrideFilter.java diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java index ab75bdc5d..e6556189a 100644 --- a/src/main/java/org/traccar/api/MediaFilter.java +++ b/src/main/java/org/traccar/api/MediaFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,6 @@ import javax.inject.Inject; import javax.inject.Singleton; import javax.servlet.Filter; import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -57,10 +56,6 @@ public class MediaFilter implements Filter { this.permissionsServiceProvider = permissionsServiceProvider; } - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @@ -99,8 +94,4 @@ public class MediaFilter implements Filter { } } - @Override - public void destroy() { - } - } diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java index 7a61eda8c..6a4f502f7 100644 --- a/src/main/java/org/traccar/model/ExtendedModel.java +++ b/src/main/java/org/traccar/model/ExtendedModel.java @@ -89,14 +89,18 @@ public class ExtendedModel extends BaseModel { } } - public String getString(String key) { + public String getString(String key, String defaultValue) { if (attributes.containsKey(key)) { return attributes.get(key).toString(); } else { - return null; + return defaultValue; } } + public String getString(String key) { + return getString(key, null); + } + public double getDouble(String key) { if (attributes.containsKey(key)) { Object value = attributes.get(key); diff --git a/src/main/java/org/traccar/web/CharResponseWrapper.java b/src/main/java/org/traccar/web/CharResponseWrapper.java new file mode 100644 index 000000000..0e7976ce0 --- /dev/null +++ b/src/main/java/org/traccar/web/CharResponseWrapper.java @@ -0,0 +1,82 @@ +/* + * 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.web; + +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class CharResponseWrapper extends HttpServletResponseWrapper { + + private final ByteArrayOutputStream capture; + private ServletOutputStream output; + + public CharResponseWrapper(HttpServletResponse response) { + super(response); + capture = new ByteArrayOutputStream(response.getBufferSize()); + } + + @Override + public ServletOutputStream getOutputStream() { + if (output == null) { + output = new ServletOutputStream() { + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + } + + @Override + public void write(int b) { + capture.write(b); + } + + @Override + public void flush() throws IOException { + capture.flush(); + } + + @Override + public void close() throws IOException { + capture.close(); + } + }; + } + return output; + } + + @Override + public void flushBuffer() throws IOException { + super.flushBuffer(); + if (output != null) { + output.flush(); + } + } + + public String getCaptureAsString() throws IOException { + if (output != null) { + output.close(); + } + return capture.toString(getCharacterEncoding()); + } + +} diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java new file mode 100644 index 000000000..cb69dfbfa --- /dev/null +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -0,0 +1,71 @@ +/* + * 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.web; + +import com.google.inject.Provider; +import org.traccar.api.security.PermissionsService; +import org.traccar.model.Server; +import org.traccar.storage.StorageException; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Singleton +public class OverrideFilter implements Filter { + + private final Provider permissionsServiceProvider; + + @Inject + public OverrideFilter(Provider permissionsServiceProvider) { + this.permissionsServiceProvider = permissionsServiceProvider; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response); + + chain.doFilter(request, wrapper); + + Server server; + try { + server = permissionsServiceProvider.get().getServer(); + } catch (StorageException e) { + throw new RuntimeException(e); + } + + String title = server.getString("serverTitle", "Traccar"); + String description = server.getString("serverDescription", "Traccar GPS Tracking System"); + String colorPrimary = server.getString("serverColorPrimary", "#1a237e"); + + String alteredContent = wrapper.getCaptureAsString() + .replace("${title}", title) + .replace("${description}", description) + .replace("${colorPrimary}", colorPrimary); + + response.setContentLength(alteredContent.length()); + response.getWriter().write(alteredContent); + } + +} diff --git a/src/main/java/org/traccar/web/WebModule.java b/src/main/java/org/traccar/web/WebModule.java index 0722c5d1e..f06abf0b5 100644 --- a/src/main/java/org/traccar/web/WebModule.java +++ b/src/main/java/org/traccar/web/WebModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -23,6 +23,8 @@ public class WebModule extends ServletModule { @Override protected void configureServlets() { + filter("/").through(OverrideFilter.class); + filter("/manifest.json").through(OverrideFilter.class); filter("/api/*").through(ThrottlingFilter.class); filter("/api/media/*").through(MediaFilter.class); serve("/api/socket").with(AsyncSocketServlet.class); -- cgit v1.2.3 From 599abc3523b93f83281d44b109676b1b0ed602f5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 May 2023 12:50:11 -0700 Subject: Rename server attributes --- src/main/java/org/traccar/web/OverrideFilter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java index cb69dfbfa..303c21253 100644 --- a/src/main/java/org/traccar/web/OverrideFilter.java +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -55,9 +55,9 @@ public class OverrideFilter implements Filter { throw new RuntimeException(e); } - String title = server.getString("serverTitle", "Traccar"); - String description = server.getString("serverDescription", "Traccar GPS Tracking System"); - String colorPrimary = server.getString("serverColorPrimary", "#1a237e"); + String title = server.getString("title", "Traccar"); + String description = server.getString("description", "Traccar GPS Tracking System"); + String colorPrimary = server.getString("colorPrimary", "#1a237e"); String alteredContent = wrapper.getCaptureAsString() .replace("${title}", title) -- cgit v1.2.3 From d5717272c664b6e09408f31a8448c80a0f380ddb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 May 2023 15:41:55 -0700 Subject: Handle modern paths --- .../java/org/traccar/web/CharResponseWrapper.java | 4 +- .../java/org/traccar/web/ModernDefaultServlet.java | 33 +++++++++++++++++ src/main/java/org/traccar/web/OverrideFilter.java | 43 +++++++++++++--------- src/main/java/org/traccar/web/WebModule.java | 3 +- src/main/java/org/traccar/web/WebServer.java | 12 ++---- 5 files changed, 65 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/traccar/web/ModernDefaultServlet.java diff --git a/src/main/java/org/traccar/web/CharResponseWrapper.java b/src/main/java/org/traccar/web/CharResponseWrapper.java index 0e7976ce0..477fe7928 100644 --- a/src/main/java/org/traccar/web/CharResponseWrapper.java +++ b/src/main/java/org/traccar/web/CharResponseWrapper.java @@ -72,11 +72,11 @@ public class CharResponseWrapper extends HttpServletResponseWrapper { } } - public String getCaptureAsString() throws IOException { + public byte[] getCapture() throws IOException { if (output != null) { output.close(); } - return capture.toString(getCharacterEncoding()); + return capture.toByteArray(); } } diff --git a/src/main/java/org/traccar/web/ModernDefaultServlet.java b/src/main/java/org/traccar/web/ModernDefaultServlet.java new file mode 100644 index 000000000..bae089d6c --- /dev/null +++ b/src/main/java/org/traccar/web/ModernDefaultServlet.java @@ -0,0 +1,33 @@ +/* + * 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.web; + +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.util.resource.Resource; + +public class ModernDefaultServlet extends DefaultServlet { + + @Override + public Resource getResource(String pathInContext) { + return super.getResource(pathInContext.indexOf('.') < 0 ? "/" : pathInContext); + } + + @Override + public String getWelcomeFile(String pathInContext) { + return super.getWelcomeFile("/"); + } + +} diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java index 303c21253..708632bc1 100644 --- a/src/main/java/org/traccar/web/OverrideFilter.java +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -27,6 +27,7 @@ import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -44,28 +45,36 @@ public class OverrideFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response); + CharResponseWrapper wrappedResponse = new CharResponseWrapper((HttpServletResponse) response); - chain.doFilter(request, wrapper); + chain.doFilter(request, wrappedResponse); - Server server; - try { - server = permissionsServiceProvider.get().getServer(); - } catch (StorageException e) { - throw new RuntimeException(e); - } + byte[] bytes = wrappedResponse.getCapture(); + if (wrappedResponse.getContentType().contains("text/html") + || ((HttpServletRequest) request).getPathInfo().endsWith("manifest.json")) { + + Server server; + try { + server = permissionsServiceProvider.get().getServer(); + } catch (StorageException e) { + throw new RuntimeException(e); + } - String title = server.getString("title", "Traccar"); - String description = server.getString("description", "Traccar GPS Tracking System"); - String colorPrimary = server.getString("colorPrimary", "#1a237e"); + String title = server.getString("title", "Traccar"); + String description = server.getString("description", "Traccar GPS Tracking System"); + String colorPrimary = server.getString("colorPrimary", "#1a237e"); - String alteredContent = wrapper.getCaptureAsString() - .replace("${title}", title) - .replace("${description}", description) - .replace("${colorPrimary}", colorPrimary); + String alteredContent = new String(wrappedResponse.getCapture()) + .replace("${title}", title) + .replace("${description}", description) + .replace("${colorPrimary}", colorPrimary); - response.setContentLength(alteredContent.length()); - response.getWriter().write(alteredContent); + response.setContentLength(alteredContent.length()); + response.getOutputStream().write(alteredContent.getBytes()); + + } else { + response.getOutputStream().write(bytes); + } } } diff --git a/src/main/java/org/traccar/web/WebModule.java b/src/main/java/org/traccar/web/WebModule.java index f06abf0b5..a32a6f447 100644 --- a/src/main/java/org/traccar/web/WebModule.java +++ b/src/main/java/org/traccar/web/WebModule.java @@ -23,8 +23,7 @@ public class WebModule extends ServletModule { @Override protected void configureServlets() { - filter("/").through(OverrideFilter.class); - filter("/manifest.json").through(OverrideFilter.class); + filter("/*").through(OverrideFilter.class); filter("/api/*").through(ThrottlingFilter.class); filter("/api/media/*").through(MediaFilter.class); serve("/api/socket").with(AsyncSocketServlet.class); diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index 79d19cc9b..29e6de9f2 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -103,14 +103,8 @@ public class WebServer implements LifecycleObject { @Override protected void handleErrorPage( HttpServletRequest request, Writer writer, int code, String message) throws IOException { - Path index = Paths.get(config.getString(Keys.WEB_PATH), "index.html"); - if (code == HttpStatus.NOT_FOUND_404 - && !request.getPathInfo().startsWith("/api/") && Files.exists(index)) { - writer.write(Files.readString(index)); - } else { - writer.write("Error" - + code + " - " + HttpStatus.getMessage(code) + ""); - } + writer.write("Error" + + code + " - " + HttpStatus.getMessage(code) + ""); } }); @@ -150,7 +144,7 @@ public class WebServer implements LifecycleObject { } private void initWebApp(ServletContextHandler servletHandler) { - ServletHolder servletHolder = new ServletHolder(DefaultServlet.class); + ServletHolder servletHolder = new ServletHolder(ModernDefaultServlet.class); servletHolder.setInitParameter("resourceBase", new File(config.getString(Keys.WEB_PATH)).getAbsolutePath()); servletHolder.setInitParameter("dirAllowed", "false"); if (config.getBoolean(Keys.WEB_DEBUG)) { -- cgit v1.2.3 From f7382adfc212750d8863bb93d84317294cdf0da8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 May 2023 15:44:25 -0700 Subject: Remove unused imports --- src/main/java/org/traccar/web/WebServer.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index 29e6de9f2..ce1220157 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -62,9 +62,6 @@ import java.io.File; import java.io.IOException; import java.io.Writer; import java.net.InetSocketAddress; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.EnumSet; public class WebServer implements LifecycleObject { -- cgit v1.2.3 From 30f09160d226fbe0133f96cdbf6f25c72e191a06 Mon Sep 17 00:00:00 2001 From: K-J-Dod24 Date: Tue, 16 May 2023 08:48:19 +0100 Subject: removed Engine temp (115) --- src/main/java/org/traccar/model/Position.java | 1 - src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index c48e34e03..3ed340703 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -81,7 +81,6 @@ public class Position extends Message { public static final String KEY_ACCELERATION = "acceleration"; public static final String KEY_DEVICE_TEMP = "deviceTemp"; // celsius public static final String KEY_COOLANT_TEMP = "coolantTemp"; // celsius - public static final String KEY_ENGINE_TEMP = "engineTemp"; // celsius public static final String KEY_ENGINE_LOAD = "engineLoad"; public static final String KEY_OPERATOR = "operator"; public static final String KEY_COMMAND = "command"; diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index d60107d7a..2f378f30a 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -248,7 +248,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { }); register(80, fmbXXX, (p, b) -> p.set("dataMode", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); - register(115, fmbXXX, (p, b) -> p.set(Position.KEY_ENGINE_TEMP, b.readShort() * 0.1)); 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)); -- cgit v1.2.3 From 8ee05feeafbf7c6356e1afd65e140823c717aef8 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Tue, 16 May 2023 16:32:54 +0300 Subject: Reafactoring --- .../traccar/protocol/TranSyncProtocolDecoder.java | 216 +++++++++------------ .../protocol/TranSyncProtocolDecoderTest.java | 7 +- 2 files changed, 98 insertions(+), 125 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index d5a69dbe2..d07b70365 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2013 - 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.buffer.ByteBuf; @@ -6,6 +21,7 @@ import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.Protocol; import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.CellTower; import org.traccar.model.Network; @@ -13,206 +29,166 @@ import org.traccar.model.Position; import org.traccar.session.DeviceSession; import java.net.SocketAddress; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; +import java.util.Arrays; public class TranSyncProtocolDecoder extends BaseProtocolDecoder { + private static final byte[] STX = new byte[]{0x3a, 0x3a}; + public TranSyncProtocolDecoder(Protocol protocol) { super(protocol); } - public Date getDatefromIntegerParameters(int year, int month, int day, int hours, int minutes, int seconds) { - - String dataString = ""+year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds; - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); - simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - try { - return simpleDateFormat.parse(dataString); - - } catch (ParseException e) { - e.printStackTrace(); - } - return null; - } - - protected void setDeviceAlert(Position position, int alert) { - switch (alert) { + protected void decodeAlarm(Position position, int value) { + switch (value) { case 10: - position.set(Position.ALARM_SOS, true); + position.set(Position.KEY_ALARM, Position.ALARM_SOS); break; case 11: - position.set(Position.ALARM_SOS, false); + position.set(Position.KEY_EVENT, 11); break; case 16: position.set(Position.KEY_EVENT, 16); break; case 3: - position.set("distressCutOff", true); + position.set(Position.KEY_ALARM, 3); break; case 22: - position.set("tilt", true); + position.set(Position.KEY_ALARM, 22); break; case 9: position.set(Position.KEY_EVENT, 9); case 17: - position.set(Position.ALARM_OVERSPEED, true); + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); break; case 13: - position.set(Position.ALARM_BRAKING, true); + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); break; case 14: - position.set(Position.ALARM_ACCELERATION, true); + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); break; case 15: position.set(Position.KEY_EVENT, 15); break; case 23: - position.set(Position.ALARM_ACCIDENT, true); + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); break; case 12: position.set(Position.KEY_EVENT, 12); break; case 6: - position.set(Position.ALARM_POWER_RESTORED, true); + position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); break; case 4: - position.set(Position.ALARM_LOW_BATTERY, true); + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); break; case 5: position.set(Position.KEY_EVENT, 5); break; - } - - } - - private void setNetwork(Position position, int lacInt, int cellIdInt, int mobileNetworkCode, int gsmSignalStrength){ - CellTower cellTower = CellTower.fromLacCid(getConfig(), lacInt, cellIdInt); - cellTower.setMobileNetworkCode(mobileNetworkCode); - cellTower.setSignalStrength(gsmSignalStrength); - position.setNetwork(new Network(cellTower)); - } - private String getTrackerModel(int mask){ + private void decodePowerEngineParameters(Position position, int value){ - switch (mask) { - case 1: - return "basic"; - case 2: - return "asset"; - case 3: - return "bike"; + position.set(Position.PREFIX_OUT + 1, BitUtil.check(value, 7)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(value, 6)); + position.set(Position.PREFIX_IN + 3, BitUtil.check(value, 5)); + if (BitUtil.check(value, 4)) position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + position.set(Position.KEY_IGNITION, BitUtil.check(value, 3)); + position.set("gpsFix", BitUtil.check(value, 0)); - case 4: - return "serial"; + } - case 5: - return "obd"; - case 6: - return "l1"; - case 7: - return "ais"; - default: - return "unknown"; + private void decodeTrackerStatusParameters(Position position, int value){ + if (BitUtil.check(value, 7)) position.set("restored", true); + if (BitUtil.check(value, 5)) { + position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); } - } - private Position parseData(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - if (ByteBufUtil.hexDump(buf, 0, 2).equalsIgnoreCase("3A3A")) { + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + ByteBuf buf = (ByteBuf) msg; + if (Arrays.equals(ByteBufUtil.getBytes(buf, 0, 2), STX)) { buf.readUnsignedShort(); } - int packetLength = buf.readByte(); - int lacInt = buf.readUnsignedShort(); - String deviceId = ByteBufUtil.hexDump(buf, buf.readerIndex(), 8).toUpperCase().trim().replaceFirst("^0+(?!$)", ""); - buf.readBytes(8); - int informationSerialNumber = buf.readUnsignedShort(); - int protocolNumber = buf.readUnsignedByte(); + buf.readByte(); //packetLength + + int locationAreaCode = buf.readUnsignedShort(); + String deviceId = ByteBufUtil.hexDump(buf.readSlice(8)); + + buf.readUnsignedShort(); //informationSerialNumber + buf.readUnsignedByte(); //protocolNumber + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); if (deviceSession == null) { return null; } - Position position = new Position(getProtocolName()); - long devicesessionId = deviceSession.getDeviceId(); - - position.setDeviceId(devicesessionId) ; + position.setDeviceId(deviceSession.getDeviceId()); position.setValid(true); - int year = buf.readUnsignedByte(); - int month = buf.readUnsignedByte(); - int day = buf.readUnsignedByte(); - int hour = buf.readUnsignedByte(); - int minute = buf.readUnsignedByte(); - int second = buf.readUnsignedByte(); - position.setTime(getDatefromIntegerParameters(year, month, day, hour, minute, second)); + position.setTime(new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .getDate()); position.setLatitude(buf.readUnsignedInt() / 1800000.0); position.setLongitude(buf.readUnsignedInt() / 1800000.0); position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); position.setCourse(buf.readUnsignedShort()); + int mobileNetworkCode = buf.readUnsignedByte(); - int cellIdInt = buf.readUnsignedShort(); - int zeroByte = buf.readUnsignedByte(); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(zeroByte, 0)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(zeroByte, 1)); - position.set(Position.PREFIX_IN + 3, BitUtil.check(zeroByte, 2)); - if (BitUtil.check(zeroByte, 3)) position.set(Position.ALARM_POWER_OFF, true); - position.set(Position.KEY_IGNITION, BitUtil.check(zeroByte, 4)); - position.set("gpsFix", BitUtil.check(zeroByte, 7)); - int oneByte = buf.readUnsignedByte(); - int deviceAlert = buf.readUnsignedByte(); - if (deviceAlert > 0) { setDeviceAlert(position, deviceAlert); } - int threeByte = buf.readUnsignedByte(); - if (!((threeByte & 0b10000000) == 0)) position.set("restored", true); - if ((threeByte & 0b00100000) != 0) { - position.set(Position.ALARM_GPS_ANTENNA_CUT, true); - position.set("gpsAlert", true); - } - position.set("model", getTrackerModel(threeByte & 0b00001111)); + int cellTowerId = buf.readUnsignedShort(); + + decodePowerEngineParameters(position, buf.readUnsignedByte()); + + buf.readUnsignedByte(); // not in use + + decodeAlarm(position, buf.readUnsignedByte()); + + decodeTrackerStatusParameters(position, buf.readUnsignedByte()); + int gsmSignalStrength = buf.readUnsignedByte(); + position.set(Position.KEY_BATTERY, (double) (buf.readUnsignedByte() / 10)); position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); position.set(Position.KEY_HDOP, buf.readUnsignedByte()); position.set(Position.PREFIX_ADC + 1, (short) buf.readUnsignedShort()); - boolean isOptionalParameters = (buf.readableBytes() > 2); - setNetwork(position, lacInt, cellIdInt, mobileNetworkCode, gsmSignalStrength); - if (isOptionalParameters) { // Always True - int odometerIndex = buf.readUnsignedByte(); + + CellTower cellTower = CellTower.fromLacCid(getConfig(), locationAreaCode, cellTowerId); + cellTower.setMobileNetworkCode(mobileNetworkCode); + cellTower.setSignalStrength(gsmSignalStrength); + + position.setNetwork(new Network(cellTower)); + + if (buf.readableBytes() > 2) { + buf.readUnsignedByte(); // odometerIndex int odometerLength = buf.readUnsignedByte(); if (odometerLength > 0) { - String odometerReading = ByteBufUtil.hexDump(buf, buf.readerIndex(), odometerLength).toUpperCase().trim().replaceFirst("^0+(?!$)", ""); - int odometer = Integer.parseInt(odometerReading); - buf.readBytes(odometerLength); + int odometer = buf.readBytes(odometerLength).readInt(); position.set(Position.KEY_ODOMETER, odometer); } if ((buf.readableBytes() > 2)) { - int rfidIndex = buf.readUnsignedByte(); - int rfidLength = buf.readUnsignedByte(); - if(rfidLength > 0) { - String rfidTagName = ByteBufUtil.hexDump(buf, buf.readerIndex(), rfidLength).toUpperCase().trim(); - buf.readBytes(rfidLength); - position.set("tag", rfidTagName); + buf.readUnsignedByte(); // tagIndex + int tagLength = buf.readUnsignedByte(); + if (tagLength > 0) { + position.set("tag", ByteBufUtil.hexDump(buf.readSlice(tagLength))); } } if ((buf.readableBytes() > 5)) { - int adcTwoIndex = buf.readUnsignedByte(); - int adcTwoLength = buf.readUnsignedByte(); - if (adcTwoLength > 0){ + buf.readUnsignedByte(); // adc2Index + int adc2Length = buf.readUnsignedByte(); + if (adc2Length > 0) { position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); } } + if ((buf.readableBytes() > 5)) { + buf.readUnsignedByte(); // adc2Index + int adc2Length = buf.readUnsignedByte(); + if (adc2Length > 0 && adc2Length <= buf.readableBytes() - 2) { + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); + } + } } - return position; } - - @Override - protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - ByteBuf buffer = (ByteBuf) msg; - return parseData(channel, remoteAddress, buffer); - } - } diff --git a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java index 1b90566d4..6cf2d0c1f 100644 --- a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java @@ -1,6 +1,5 @@ package org.traccar.protocol; - import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; @@ -11,12 +10,10 @@ public class TranSyncProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TranSyncProtocolDecoder(null)); - verifyPosition(decoder, binary( - "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323")); + "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000100000050252ee060200822323")); verifyAttributes(decoder, binary( - "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323") - ); + "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323")); } } -- cgit v1.2.3 From b2e889abf0850aa568353f923a3b3f35008a063e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 16 May 2023 09:27:41 -0700 Subject: Decode VL502 DTCs --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 10 ++++++++-- .../java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 4beee7696..d3c312f7e 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -41,6 +41,7 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.TimeZone; +import java.util.stream.Collectors; public class HuabaoProtocolDecoder extends BaseProtocolDecoder { @@ -919,14 +920,19 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.setTime(time); break; case 0x02: - count = buf.readUnsignedByte(); + List codes = new LinkedList<>(); + count = buf.readUnsignedShort(); for (int i = 0; i < count; i++) { buf.readUnsignedInt(); // system id int codeCount = buf.readUnsignedShort(); for (int j = 0; j < codeCount; j++) { - buf.skipBytes(16); // code + buf.readUnsignedInt(); // dtc + buf.readUnsignedInt(); // status + codes.add(buf.readCharSequence( + buf.readUnsignedShort(), StandardCharsets.US_ASCII).toString().trim()); } } + position.set(Position.KEY_DTCS, String.join(" ", codes)); getLastLocation(position, time); decodeCoordinates(position, buf); position.setTime(time); diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 2f317d049..5fd9ed894 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyAttribute(decoder, binary( + "7e090000344f07788ef87d0138f02305151230460102020001ffffffff000100001457000000020006503134353700000c000a029dc63004b99a98230515132726787e"), + Position.KEY_DTCS, "P1457"); + verifyAttribute(decoder, binary( "7e0200006476806111898300710000000000100046005d3156065f7128000000000000230511165956660b01fe000001031a5d1a8101670831333231343332326902018b6a01166b01006c0f323034303830393230373533363735711438393434343738383030303030323131303030464b7e"), Position.KEY_BATTERY, 3.95); -- cgit v1.2.3 From fbd3ee0d77673d94766a87aa67c05885e44aa7e5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 16 May 2023 09:28:30 -0700 Subject: Remove unused import --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index d3c312f7e..ee5ab19d6 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -41,7 +41,6 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.TimeZone; -import java.util.stream.Collectors; public class HuabaoProtocolDecoder extends BaseProtocolDecoder { -- cgit v1.2.3 From 7e403cf979d3c01acb5b3dfe0ee37dfa83cba4ff Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Wed, 17 May 2023 11:00:43 +0300 Subject: Add LengthFieldBasedFrameDecoder to TranSyncProtocol --- .../java/org/traccar/protocol/TranSyncProtocol.java | 19 ++++++++++++++++++- .../org/traccar/protocol/TranSyncProtocolDecoder.java | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java index 0634642df..39db67585 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocol.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java @@ -1,5 +1,22 @@ +/* + * Copyright 2013 - 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.LengthFieldBasedFrameDecoder; +import io.netty.handler.codec.LineBasedFrameDecoder; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; @@ -14,9 +31,9 @@ public class TranSyncProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0, true)); pipeline.addLast(new TranSyncProtocolDecoder(TranSyncProtocol.this)); } }); } - } diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index d07b70365..bb8c9bbf9 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -17,8 +17,10 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; @@ -106,6 +108,18 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } } + private void sendResponse(Channel channel) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(5); + response.writeByte(22); + response.writeByte(1); + response.writeShort(response.capacity()); // length + response.writeByte(4); + + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + @Override protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; @@ -189,6 +203,7 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } } } + sendResponse(channel); return position; } } -- cgit v1.2.3 From 9fa4b44281e96ab56f3a0d27745d89265ea417fd Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Wed, 17 May 2023 11:13:43 +0300 Subject: Remove sendResponse function from TranSyncProtocolDecoder.java --- .../java/org/traccar/protocol/TranSyncProtocolDecoder.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index bb8c9bbf9..e9247ddf8 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -108,18 +108,6 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } } - private void sendResponse(Channel channel) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(5); - response.writeByte(22); - response.writeByte(1); - response.writeShort(response.capacity()); // length - response.writeByte(4); - - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - @Override protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; @@ -203,7 +191,6 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } } } - sendResponse(channel); return position; } } -- cgit v1.2.3 From b7d46d78adc763eea3aae838f4e056e12e2dc487 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Wed, 17 May 2023 11:43:53 +0300 Subject: Add Position.KEY_ARCHIVE position parameter in decodeTrackerStatusParameters in TranSyncProtocol Add Position.KEY_VERSION_HW position parameter in decodeTrackerStatusParameters in TranSyncProtocol --- .../org/traccar/protocol/TranSyncProtocol.java | 3 +-- .../traccar/protocol/TranSyncProtocolDecoder.java | 29 +++++++++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java index 39db67585..3abe05de8 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocol.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java @@ -16,7 +16,6 @@ package org.traccar.protocol; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import io.netty.handler.codec.LineBasedFrameDecoder; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; @@ -36,4 +35,4 @@ public class TranSyncProtocol extends BaseProtocol { } }); } -} +} \ No newline at end of file diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index e9247ddf8..759c012b8 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -17,10 +17,8 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; @@ -37,6 +35,28 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { private static final byte[] STX = new byte[]{0x3a, 0x3a}; + private String getHardwareType(int type){ + + switch (type) { + case 1: + return "basic"; + case 2: + return "asset"; + case 3: + return "bike"; + case 4: + return "serial"; + case 5: + return "obd"; + case 6: + return "l1"; + case 7: + return "ais-140"; + default: + return "unknown"; + } + } + public TranSyncProtocolDecoder(Protocol protocol) { super(protocol); } @@ -102,10 +122,11 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } private void decodeTrackerStatusParameters(Position position, int value){ - if (BitUtil.check(value, 7)) position.set("restored", true); + if (BitUtil.check(value, 7)) position.set(Position.KEY_ARCHIVE, true); if (BitUtil.check(value, 5)) { position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); } + position.set(Position.KEY_VERSION_HW, getHardwareType(BitUtil.between(value, 0, 3))); } @Override @@ -143,7 +164,7 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { decodePowerEngineParameters(position, buf.readUnsignedByte()); - buf.readUnsignedByte(); // not in use + buf.readUnsignedByte(); // reserved decodeAlarm(position, buf.readUnsignedByte()); -- cgit v1.2.3 From 34f6dfbf1d2c48ae932fa7565dd30d2817d2c1f9 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Wed, 17 May 2023 12:10:17 +0300 Subject: remove extra empty lines --- src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java | 8 +++++--- .../java/org/traccar/protocol/TranSyncProtocolDecoderTest.java | 6 ++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index 759c012b8..acb46ec48 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -131,7 +131,9 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { @Override protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + ByteBuf buf = (ByteBuf) msg; + if (Arrays.equals(ByteBufUtil.getBytes(buf, 0, 2), STX)) { buf.readUnsignedShort(); } @@ -183,14 +185,14 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(new Network(cellTower)); - if (buf.readableBytes() > 2) { + if (buf.readableBytes() > 5) { buf.readUnsignedByte(); // odometerIndex int odometerLength = buf.readUnsignedByte(); if (odometerLength > 0) { int odometer = buf.readBytes(odometerLength).readInt(); position.set(Position.KEY_ODOMETER, odometer); } - if ((buf.readableBytes() > 2)) { + if ((buf.readableBytes() > 5)) { buf.readUnsignedByte(); // tagIndex int tagLength = buf.readUnsignedByte(); if (tagLength > 0) { @@ -205,7 +207,7 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } } if ((buf.readableBytes() > 5)) { - buf.readUnsignedByte(); // adc2Index + buf.readUnsignedByte(); // adc3Index int adc2Length = buf.readUnsignedByte(); if (adc2Length > 0 && adc2Length <= buf.readableBytes() - 2) { position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); diff --git a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java index 6cf2d0c1f..c84ae2e0f 100644 --- a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java @@ -10,10 +10,8 @@ public class TranSyncProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TranSyncProtocolDecoder(null)); - verifyPosition(decoder, binary( - "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000100000050252ee060200822323")); + verifyPosition(decoder, binary("3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000100000050252ee060200822323")); - verifyAttributes(decoder, binary( - "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323")); + verifyAttributes(decoder, binary("3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323")); } } -- cgit v1.2.3 From 074dc016d21f9848140d125c2812d8abf25e8d53 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Wed, 17 May 2023 20:29:37 +0300 Subject: Fix Pythonic ussues --- src/main/java/org/traccar/protocol/TranSyncProtocol.java | 2 +- .../org/traccar/protocol/TranSyncProtocolDecoder.java | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java index 3abe05de8..5422380b6 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocol.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java @@ -35,4 +35,4 @@ public class TranSyncProtocol extends BaseProtocol { } }); } -} \ No newline at end of file +} diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index acb46ec48..1b7c9539c 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -35,7 +35,7 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { private static final byte[] STX = new byte[]{0x3a, 0x3a}; - private String getHardwareType(int type){ + private String getHardwareType(int type) { switch (type) { case 1: @@ -107,22 +107,28 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { case 5: position.set(Position.KEY_EVENT, 5); break; + default: + position.set(Position.KEY_EVENT, "unknown"); } } - private void decodePowerEngineParameters(Position position, int value){ + private void decodePowerEngineParameters(Position position, int value) { position.set(Position.PREFIX_OUT + 1, BitUtil.check(value, 7)); position.set(Position.PREFIX_OUT + 2, BitUtil.check(value, 6)); position.set(Position.PREFIX_IN + 3, BitUtil.check(value, 5)); - if (BitUtil.check(value, 4)) position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + if (BitUtil.check(value, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + } position.set(Position.KEY_IGNITION, BitUtil.check(value, 3)); position.set("gpsFix", BitUtil.check(value, 0)); } - private void decodeTrackerStatusParameters(Position position, int value){ - if (BitUtil.check(value, 7)) position.set(Position.KEY_ARCHIVE, true); + private void decodeTrackerStatusParameters(Position position, int value) { + if (BitUtil.check(value, 7)) { + position.set(Position.KEY_ARCHIVE, true); + } if (BitUtil.check(value, 5)) { position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); } -- cgit v1.2.3 From 05a73b06f94e451239ebc61ebb2b8528705bbc61 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Thu, 18 May 2023 12:47:40 +0300 Subject: Fix Latitude/Longitude Formats for negative support Add analizeNegativePosition function in TranSyncProtocolDecoder.java Add statusParameters variable for byte --- .../java/org/traccar/protocol/TranSyncProtocolDecoder.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index 1b7c9539c..130c916b1 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -111,6 +111,15 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_EVENT, "unknown"); } } + private void analizeNegativePosition(Position position, int value) { + + if (!BitUtil.check(value, 1)) { + position.setLatitude(-position.getLatitude()); // 0/1 S/N + } + if (!BitUtil.check(value, 2)) { + position.setLongitude(-position.getLongitude()); // 0/1 W/E + } + } private void decodePowerEngineParameters(Position position, int value) { @@ -122,7 +131,6 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { } position.set(Position.KEY_IGNITION, BitUtil.check(value, 3)); position.set("gpsFix", BitUtil.check(value, 0)); - } private void decodeTrackerStatusParameters(Position position, int value) { @@ -169,8 +177,10 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { int mobileNetworkCode = buf.readUnsignedByte(); int cellTowerId = buf.readUnsignedShort(); + int statusParameters = buf.readUnsignedByte(); - decodePowerEngineParameters(position, buf.readUnsignedByte()); + decodePowerEngineParameters(position, statusParameters); + analizeNegativePosition(position, statusParameters); buf.readUnsignedByte(); // reserved -- cgit v1.2.3 From 0e8057c605e38ecae49c6c69941a46075507302a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 18 May 2023 07:55:34 -0700 Subject: Clean up TranSync decoder --- setup/default.xml | 1 + .../org/traccar/protocol/TranSyncProtocol.java | 5 +- .../traccar/protocol/TranSyncProtocolDecoder.java | 227 +++++++-------------- .../protocol/TranSyncProtocolDecoderTest.java | 8 +- 4 files changed, 89 insertions(+), 152 deletions(-) diff --git a/setup/default.xml b/setup/default.xml index ff8ecf589..e8dc7aa79 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -288,5 +288,6 @@ 5244 5245 5246 + 5247 diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java index 5422380b6..fcc02a781 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocol.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2023 Anton Tananaev (anton@traccar.org) + * 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. @@ -30,9 +30,10 @@ public class TranSyncProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0, true)); + pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0)); pipeline.addLast(new TranSyncProtocolDecoder(TranSyncProtocol.this)); } }); } + } diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java index 130c916b1..816b5d2cf 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2023 Anton Tananaev (anton@traccar.org) + * 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. @@ -29,118 +29,32 @@ import org.traccar.model.Position; import org.traccar.session.DeviceSession; import java.net.SocketAddress; -import java.util.Arrays; public class TranSyncProtocolDecoder extends BaseProtocolDecoder { - private static final byte[] STX = new byte[]{0x3a, 0x3a}; - - private String getHardwareType(int type) { - - switch (type) { - case 1: - return "basic"; - case 2: - return "asset"; - case 3: - return "bike"; - case 4: - return "serial"; - case 5: - return "obd"; - case 6: - return "l1"; - case 7: - return "ais-140"; - default: - return "unknown"; - } - } - public TranSyncProtocolDecoder(Protocol protocol) { super(protocol); } - protected void decodeAlarm(Position position, int value) { + private String decodeAlarm(int value) { switch (value) { + case 4: + return Position.ALARM_LOW_BATTERY; + case 6: + return Position.ALARM_POWER_RESTORED; case 10: - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - break; - case 11: - position.set(Position.KEY_EVENT, 11); - break; - case 16: - position.set(Position.KEY_EVENT, 16); - break; - case 3: - position.set(Position.KEY_ALARM, 3); - break; - case 22: - position.set(Position.KEY_ALARM, 22); - break; - case 9: - position.set(Position.KEY_EVENT, 9); - case 17: - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - break; + return Position.ALARM_SOS; case 13: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; + return Position.ALARM_BRAKING; case 14: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 15: - position.set(Position.KEY_EVENT, 15); - break; + return Position.ALARM_ACCELERATION; + case 17: + return Position.ALARM_OVERSPEED; case 23: - position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); - break; - case 12: - position.set(Position.KEY_EVENT, 12); - break; - case 6: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); - break; - case 4: - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case 5: - position.set(Position.KEY_EVENT, 5); - break; + return Position.ALARM_ACCIDENT; default: - position.set(Position.KEY_EVENT, "unknown"); - } - } - private void analizeNegativePosition(Position position, int value) { - - if (!BitUtil.check(value, 1)) { - position.setLatitude(-position.getLatitude()); // 0/1 S/N - } - if (!BitUtil.check(value, 2)) { - position.setLongitude(-position.getLongitude()); // 0/1 W/E - } - } - - private void decodePowerEngineParameters(Position position, int value) { - - position.set(Position.PREFIX_OUT + 1, BitUtil.check(value, 7)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(value, 6)); - position.set(Position.PREFIX_IN + 3, BitUtil.check(value, 5)); - if (BitUtil.check(value, 4)) { - position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); - } - position.set(Position.KEY_IGNITION, BitUtil.check(value, 3)); - position.set("gpsFix", BitUtil.check(value, 0)); - } - - private void decodeTrackerStatusParameters(Position position, int value) { - if (BitUtil.check(value, 7)) { - position.set(Position.KEY_ARCHIVE, true); - } - if (BitUtil.check(value, 5)) { - position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); + return null; } - position.set(Position.KEY_VERSION_HW, getHardwareType(BitUtil.between(value, 0, 3))); } @Override @@ -148,88 +62,105 @@ public class TranSyncProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; - if (Arrays.equals(ByteBufUtil.getBytes(buf, 0, 2), STX)) { - buf.readUnsignedShort(); - } - buf.readByte(); //packetLength - - int locationAreaCode = buf.readUnsignedShort(); - String deviceId = ByteBufUtil.hexDump(buf.readSlice(8)); + buf.readUnsignedShort(); // header + buf.readByte(); // length - buf.readUnsignedShort(); //informationSerialNumber - buf.readUnsignedByte(); //protocolNumber + int lac = buf.readUnsignedShort(); + String deviceId = ByteBufUtil.hexDump(buf.readSlice(8)); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); if (deviceSession == null) { return null; } + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); + + buf.readUnsignedShort(); // index + buf.readUnsignedByte(); // type + position.setTime(new DateBuilder() .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) .getDate()); - position.setLatitude(buf.readUnsignedInt() / 1800000.0); - position.setLongitude(buf.readUnsignedInt() / 1800000.0); + + double latitude = buf.readUnsignedInt() / 1800000.0; + double longitude = buf.readUnsignedInt() / 1800000.0; + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); position.setCourse(buf.readUnsignedShort()); - int mobileNetworkCode = buf.readUnsignedByte(); - int cellTowerId = buf.readUnsignedShort(); - int statusParameters = buf.readUnsignedByte(); + int mnc = buf.readUnsignedByte(); + int cid = buf.readUnsignedShort(); + int status0 = buf.readUnsignedByte(); - decodePowerEngineParameters(position, statusParameters); - analizeNegativePosition(position, statusParameters); + position.setValid(BitUtil.check(status0, 0)); + position.setLatitude(BitUtil.check(status0, 1) ? latitude : -latitude); + position.setLongitude(BitUtil.check(status0, 2) ? longitude : -longitude); + + position.set(Position.PREFIX_OUT + 1, BitUtil.check(status0, 7)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(status0, 6)); + position.set(Position.PREFIX_IN + 3, BitUtil.check(status0, 5)); + if (BitUtil.check(status0, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + } + position.set(Position.KEY_IGNITION, BitUtil.check(status0, 3)); buf.readUnsignedByte(); // reserved - decodeAlarm(position, buf.readUnsignedByte()); + int event = buf.readUnsignedByte(); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); - decodeTrackerStatusParameters(position, buf.readUnsignedByte()); + int status3 = buf.readUnsignedByte(); + if (BitUtil.check(status3, 7)) { + position.set(Position.KEY_ARCHIVE, true); + } + if (BitUtil.check(status3, 5)) { + position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); + } - int gsmSignalStrength = buf.readUnsignedByte(); + int rssi = buf.readUnsignedByte(); + CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid); + cellTower.setMobileNetworkCode(mnc); + cellTower.setSignalStrength(rssi); + position.setNetwork(new Network(cellTower)); position.set(Position.KEY_BATTERY, (double) (buf.readUnsignedByte() / 10)); position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); position.set(Position.KEY_HDOP, buf.readUnsignedByte()); position.set(Position.PREFIX_ADC + 1, (short) buf.readUnsignedShort()); - CellTower cellTower = CellTower.fromLacCid(getConfig(), locationAreaCode, cellTowerId); - cellTower.setMobileNetworkCode(mobileNetworkCode); - cellTower.setSignalStrength(gsmSignalStrength); - - position.setNetwork(new Network(cellTower)); - if (buf.readableBytes() > 5) { - buf.readUnsignedByte(); // odometerIndex - int odometerLength = buf.readUnsignedByte(); - if (odometerLength > 0) { - int odometer = buf.readBytes(odometerLength).readInt(); - position.set(Position.KEY_ODOMETER, odometer); + buf.readUnsignedByte(); // odometer id + int length = buf.readUnsignedByte(); + if (length > 0) { + position.set(Position.KEY_ODOMETER, buf.readBytes(length).readInt()); } - if ((buf.readableBytes() > 5)) { - buf.readUnsignedByte(); // tagIndex - int tagLength = buf.readUnsignedByte(); - if (tagLength > 0) { - position.set("tag", ByteBufUtil.hexDump(buf.readSlice(tagLength))); - } + } + if (buf.readableBytes() > 5) { + buf.readUnsignedByte(); // rfid id + int length = buf.readUnsignedByte(); + if (length > 0) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, ByteBufUtil.hexDump(buf.readSlice(length))); } - if ((buf.readableBytes() > 5)) { - buf.readUnsignedByte(); // adc2Index - int adc2Length = buf.readUnsignedByte(); - if (adc2Length > 0) { - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - } + } + if (buf.readableBytes() > 5) { + buf.readUnsignedByte(); // adc2 id + int length = buf.readUnsignedByte(); + if (length > 0) { + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); } - if ((buf.readableBytes() > 5)) { - buf.readUnsignedByte(); // adc3Index - int adc2Length = buf.readUnsignedByte(); - if (adc2Length > 0 && adc2Length <= buf.readableBytes() - 2) { - position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); - } + } + if (buf.readableBytes() > 5) { + buf.readUnsignedByte(); // adc3 id + int length = buf.readUnsignedByte(); + if (length > 0 && length <= buf.readableBytes() - 2) { + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); } } + return position; } + } diff --git a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java index c84ae2e0f..27f53b574 100644 --- a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java @@ -10,8 +10,12 @@ public class TranSyncProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TranSyncProtocolDecoder(null)); - verifyPosition(decoder, binary("3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000100000050252ee060200822323")); + verifyPosition(decoder, binary( + "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000100000050252ee060200822323")); + + verifyAttributes(decoder, binary( + "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323")); - verifyAttributes(decoder, binary("3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323")); } + } -- cgit v1.2.3 From 1e1e55537a6fcb2d5365ea2cbcb9c182d986e83a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 18 May 2023 15:32:19 -0700 Subject: Fix response wrapper --- .../java/org/traccar/web/CharResponseWrapper.java | 82 ---------------------- src/main/java/org/traccar/web/OverrideFilter.java | 4 +- src/main/java/org/traccar/web/ResponseWrapper.java | 82 ++++++++++++++++++++++ 3 files changed, 84 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/org/traccar/web/CharResponseWrapper.java create mode 100644 src/main/java/org/traccar/web/ResponseWrapper.java diff --git a/src/main/java/org/traccar/web/CharResponseWrapper.java b/src/main/java/org/traccar/web/CharResponseWrapper.java deleted file mode 100644 index 477fe7928..000000000 --- a/src/main/java/org/traccar/web/CharResponseWrapper.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.web; - -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class CharResponseWrapper extends HttpServletResponseWrapper { - - private final ByteArrayOutputStream capture; - private ServletOutputStream output; - - public CharResponseWrapper(HttpServletResponse response) { - super(response); - capture = new ByteArrayOutputStream(response.getBufferSize()); - } - - @Override - public ServletOutputStream getOutputStream() { - if (output == null) { - output = new ServletOutputStream() { - @Override - public boolean isReady() { - return true; - } - - @Override - public void setWriteListener(WriteListener writeListener) { - } - - @Override - public void write(int b) { - capture.write(b); - } - - @Override - public void flush() throws IOException { - capture.flush(); - } - - @Override - public void close() throws IOException { - capture.close(); - } - }; - } - return output; - } - - @Override - public void flushBuffer() throws IOException { - super.flushBuffer(); - if (output != null) { - output.flush(); - } - } - - public byte[] getCapture() throws IOException { - if (output != null) { - output.close(); - } - return capture.toByteArray(); - } - -} diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java index 708632bc1..e6e02514c 100644 --- a/src/main/java/org/traccar/web/OverrideFilter.java +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -45,12 +45,12 @@ public class OverrideFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - CharResponseWrapper wrappedResponse = new CharResponseWrapper((HttpServletResponse) response); + ResponseWrapper wrappedResponse = new ResponseWrapper((HttpServletResponse) response); chain.doFilter(request, wrappedResponse); byte[] bytes = wrappedResponse.getCapture(); - if (wrappedResponse.getContentType().contains("text/html") + if (wrappedResponse.getContentType() != null && wrappedResponse.getContentType().contains("text/html") || ((HttpServletRequest) request).getPathInfo().endsWith("manifest.json")) { Server server; diff --git a/src/main/java/org/traccar/web/ResponseWrapper.java b/src/main/java/org/traccar/web/ResponseWrapper.java new file mode 100644 index 000000000..7c06b67b8 --- /dev/null +++ b/src/main/java/org/traccar/web/ResponseWrapper.java @@ -0,0 +1,82 @@ +/* + * 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.web; + +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class ResponseWrapper extends HttpServletResponseWrapper { + + private final ByteArrayOutputStream capture; + private ServletOutputStream output; + + public ResponseWrapper(HttpServletResponse response) { + super(response); + capture = new ByteArrayOutputStream(response.getBufferSize()); + } + + @Override + public ServletOutputStream getOutputStream() { + if (output == null) { + output = new ServletOutputStream() { + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + } + + @Override + public void write(int b) { + capture.write(b); + } + + @Override + public void flush() throws IOException { + capture.flush(); + } + + @Override + public void close() throws IOException { + capture.close(); + } + }; + } + return output; + } + + @Override + public void flushBuffer() throws IOException { + super.flushBuffer(); + if (output != null) { + output.flush(); + } + } + + public byte[] getCapture() throws IOException { + if (output != null) { + output.close(); + } + return capture.toByteArray(); + } + +} -- cgit v1.2.3 From 39b293b9f66c3c539e180fb2bcf37849335100dc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 18 May 2023 16:16:10 -0700 Subject: Fix override filter --- src/main/java/org/traccar/web/OverrideFilter.java | 40 ++++++++++++---------- src/main/java/org/traccar/web/ResponseWrapper.java | 3 +- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java index e6e02514c..70eb80a67 100644 --- a/src/main/java/org/traccar/web/OverrideFilter.java +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -50,30 +50,32 @@ public class OverrideFilter implements Filter { chain.doFilter(request, wrappedResponse); byte[] bytes = wrappedResponse.getCapture(); - if (wrappedResponse.getContentType() != null && wrappedResponse.getContentType().contains("text/html") - || ((HttpServletRequest) request).getPathInfo().endsWith("manifest.json")) { + if (bytes != null) { + if (wrappedResponse.getContentType() != null && wrappedResponse.getContentType().contains("text/html") + || ((HttpServletRequest) request).getPathInfo().endsWith("manifest.json")) { - Server server; - try { - server = permissionsServiceProvider.get().getServer(); - } catch (StorageException e) { - throw new RuntimeException(e); - } + Server server; + try { + server = permissionsServiceProvider.get().getServer(); + } catch (StorageException e) { + throw new RuntimeException(e); + } - String title = server.getString("title", "Traccar"); - String description = server.getString("description", "Traccar GPS Tracking System"); - String colorPrimary = server.getString("colorPrimary", "#1a237e"); + String title = server.getString("title", "Traccar"); + String description = server.getString("description", "Traccar GPS Tracking System"); + String colorPrimary = server.getString("colorPrimary", "#1a237e"); - String alteredContent = new String(wrappedResponse.getCapture()) - .replace("${title}", title) - .replace("${description}", description) - .replace("${colorPrimary}", colorPrimary); + String alteredContent = new String(wrappedResponse.getCapture()) + .replace("${title}", title) + .replace("${description}", description) + .replace("${colorPrimary}", colorPrimary); - response.setContentLength(alteredContent.length()); - response.getOutputStream().write(alteredContent.getBytes()); + response.setContentLength(alteredContent.length()); + response.getOutputStream().write(alteredContent.getBytes()); - } else { - response.getOutputStream().write(bytes); + } else { + response.getOutputStream().write(bytes); + } } } diff --git a/src/main/java/org/traccar/web/ResponseWrapper.java b/src/main/java/org/traccar/web/ResponseWrapper.java index 7c06b67b8..c6179a33e 100644 --- a/src/main/java/org/traccar/web/ResponseWrapper.java +++ b/src/main/java/org/traccar/web/ResponseWrapper.java @@ -75,8 +75,9 @@ public class ResponseWrapper extends HttpServletResponseWrapper { public byte[] getCapture() throws IOException { if (output != null) { output.close(); + return capture.toByteArray(); } - return capture.toByteArray(); + return null; } } -- cgit v1.2.3 From ebc3ab93b63006c77802c45c793f3a875982dbba Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 18 May 2023 16:42:22 -0700 Subject: Support web overrides --- src/main/java/org/traccar/config/Keys.java | 7 ++++++ .../java/org/traccar/web/ModernDefaultServlet.java | 26 ++++++++++++++++++++++ src/main/java/org/traccar/web/WebServer.java | 4 ++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 162a3fe13..4ebdd49f1 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -753,6 +753,13 @@ public final class Keys { "web.path", List.of(KeyType.CONFIG)); + /** + * Path to a folder with overrides. It can be used for branding to keep custom logos in a separate place. + */ + public static final ConfigKey WEB_OVERRIDE = new StringConfigKey( + "web.override", + List.of(KeyType.CONFIG)); + /** * WebSocket connection timeout in milliseconds. Default timeout is 10 minutes. */ diff --git a/src/main/java/org/traccar/web/ModernDefaultServlet.java b/src/main/java/org/traccar/web/ModernDefaultServlet.java index bae089d6c..7911c0e7f 100644 --- a/src/main/java/org/traccar/web/ModernDefaultServlet.java +++ b/src/main/java/org/traccar/web/ModernDefaultServlet.java @@ -17,11 +17,37 @@ package org.traccar.web; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.util.resource.Resource; +import org.traccar.config.Config; +import org.traccar.config.Keys; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; public class ModernDefaultServlet extends DefaultServlet { + private Resource overrideResource; + + @Inject + public ModernDefaultServlet(Config config) { + String override = config.getString(Keys.WEB_OVERRIDE); + if (override != null) { + overrideResource = Resource.newResource(new File(override)); + } + } + @Override public Resource getResource(String pathInContext) { + if (overrideResource != null) { + try { + Resource override = overrideResource.addPath(pathInContext); + if (override.exists()) { + return override; + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } return super.getResource(pathInContext.indexOf('.') < 0 ? "/" : pathInContext); } diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index ce1220157..b5d2f2771 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -141,7 +141,7 @@ public class WebServer implements LifecycleObject { } private void initWebApp(ServletContextHandler servletHandler) { - ServletHolder servletHolder = new ServletHolder(ModernDefaultServlet.class); + ServletHolder servletHolder = new ServletHolder(new ModernDefaultServlet(config)); servletHolder.setInitParameter("resourceBase", new File(config.getString(Keys.WEB_PATH)).getAbsolutePath()); servletHolder.setInitParameter("dirAllowed", "false"); if (config.getBoolean(Keys.WEB_DEBUG)) { -- cgit v1.2.3 From f7731b12156019cafb434ada7183db54cfe76a99 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 19 May 2023 07:49:48 -0700 Subject: Try new CI config --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a157037a5..bbe1ec79f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,9 +40,11 @@ jobs: echo "$HOME/bin/Sencha/Cmd/" >> $GITHUB_PATH - run: ./traccar-web/tools/package.sh - run: | + sudo apt-get update + sudo apt-get install innoextract makeself s3cmd libc6:i386 sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install innoextract makeself wine32 s3cmd + sudo apt-get install wine32 - name: Build installers working-directory: ./setup run: | -- cgit v1.2.3 From 6f55411b41d06eed327c4349ed2a4d104443d7b8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 19 May 2023 08:05:04 -0700 Subject: Try new CI config --- .github/workflows/release.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bbe1ec79f..a8e4c5369 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,11 +40,10 @@ jobs: echo "$HOME/bin/Sencha/Cmd/" >> $GITHUB_PATH - run: ./traccar-web/tools/package.sh - run: | - sudo apt-get update - sudo apt-get install innoextract makeself s3cmd libc6:i386 sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install wine32 + sudo apt-get install libgcc-s1:i386 libstdc++6:i386 + sudo apt-get install innoextract makeself wine32 s3cmd - name: Build installers working-directory: ./setup run: | -- cgit v1.2.3 From 48dae92ed4cda1acdb76f0a9250f545f3bca977a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 19 May 2023 15:28:06 -0700 Subject: Update MySQL URL --- setup/cloud-init.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/cloud-init.yaml b/setup/cloud-init.yaml index 4ca2e3ed2..1246fb1b7 100644 --- a/setup/cloud-init.yaml +++ b/setup/cloud-init.yaml @@ -9,7 +9,7 @@ write_files: ./conf/default.xml com.mysql.jdbc.Driver - jdbc:mysql://localhost/traccar?serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false&allowMultiQueries=true&autoReconnect=true&useUnicode=yes&characterEncoding=UTF-8&sessionVariables=sql_mode='' + jdbc:mysql://localhost/traccar?zeroDateTimeBehavior=round&serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false&allowMultiQueries=true&autoReconnect=true&useUnicode=yes&characterEncoding=UTF-8&sessionVariables=sql_mode='' root root -- cgit v1.2.3 From e94e7f55aae161cf2fd30bbb2ca217f23627b074 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 22 May 2023 17:21:52 -0700 Subject: Add SMS enabled flag --- src/main/java/org/traccar/api/resource/ServerResource.java | 8 +++++++- src/main/java/org/traccar/model/Server.java | 14 +++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 6a3b8919e..f334b7a21 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -25,6 +25,7 @@ import org.traccar.helper.LogAction; import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.session.cache.CacheManager; +import org.traccar.sms.SmsManager; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; @@ -56,6 +57,10 @@ public class ServerResource extends BaseResource { @Inject private MailManager mailManager; + @Inject + @Nullable + private SmsManager smsManager; + @Inject @Nullable private OpenIdProvider openIdProvider; @@ -69,6 +74,7 @@ public class ServerResource extends BaseResource { public Server get() throws StorageException { Server server = storage.getObject(Server.class, new Request(new Columns.All())); server.setEmailEnabled(mailManager.getEmailEnabled()); + server.setTextEnabled(smsManager != null); server.setGeocoderEnabled(geocoder != null); server.setOpenIdEnabled(openIdProvider != null); server.setOpenIdForce(openIdProvider != null && openIdProvider.getForce()); diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index b790ca472..6442186b6 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -228,6 +228,18 @@ public class Server extends ExtendedModel implements UserRestrictions { private boolean geocoderEnabled; + private boolean textEnabled; + + @QueryIgnore + public void setTextEnabled(boolean textEnabled) { + this.textEnabled = textEnabled; + } + + @QueryIgnore + public Boolean getTextEnabled() { + return textEnabled; + } + @QueryIgnore public void setGeocoderEnabled(boolean geocoderEnabled) { this.geocoderEnabled = geocoderEnabled; -- cgit v1.2.3 From e9a93ff35c1f923245ffdde78e4023b434173d64 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 23 May 2023 16:17:34 -0700 Subject: Fast summary report --- src/main/java/org/traccar/config/Keys.java | 9 ++ .../org/traccar/reports/SummaryReportProvider.java | 120 ++++++++++++--------- 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 4ebdd49f1..8246fdeac 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1170,6 +1170,15 @@ public final class Keys { "report.periodLimit", List.of(KeyType.CONFIG)); + /** + * Time threshold for fast reports. Fast reports are more efficient, but less accurate and missing some information. + * The value is in seconds. One day by default. + */ + public static final ConfigKey REPORT_FAST_THRESHOLD = new LongConfigKey( + "report.fastThreshold", + List.of(KeyType.CONFIG), + 86400L); + /** * Trips less than minimal duration and minimal distance are ignored. 300 seconds and 500 meters are default. */ diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index f7d9f0325..2226263fa 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +30,10 @@ import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.SummaryReportItem; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; import javax.inject.Inject; import java.io.File; @@ -38,10 +42,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Paths; +import java.time.Duration; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Calendar; import java.util.Collection; import java.util.Date; +import java.util.List; public class SummaryReportProvider { @@ -59,96 +66,105 @@ public class SummaryReportProvider { this.storage = storage; } - private SummaryReportItem calculateSummaryResult(Device device, Collection positions) { + private Position getEdgePosition(long deviceId, Date from, Date to, boolean end) throws StorageException { + return storage.getObject(Position.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", deviceId), + new Condition.Between("fixTime", "from", from, "to", to)), + new Order("fixTime", end, 1))); + } + + private Collection calculateDeviceResult( + Device device, Date from, Date to, boolean fast) throws StorageException { + SummaryReportItem result = new SummaryReportItem(); result.setDeviceId(device.getId()); result.setDeviceName(device.getName()); - if (positions != null && !positions.isEmpty()) { - Position firstPosition = null; - Position previousPosition = null; + + Position first = null; + Position last = null; + if (fast) { + first = getEdgePosition(device.getId(), from, to, false); + last = getEdgePosition(device.getId(), from, to, true); + } else { + var positions = PositionUtil.getPositions(storage, device.getId(), from, to); for (Position position : positions) { - if (firstPosition == null) { - firstPosition = position; + if (first == null) { + first = position; } - previousPosition = position; if (position.getSpeed() > result.getMaxSpeed()) { result.setMaxSpeed(position.getSpeed()); } + last = position; } + } + + if (first != null && last != null) { boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER); - result.setDistance(PositionUtil.calculateDistance(firstPosition, previousPosition, !ignoreOdometer)); - result.setSpentFuel(reportUtils.calculateFuel(firstPosition, previousPosition)); + result.setDistance(PositionUtil.calculateDistance(first, last, !ignoreOdometer)); + result.setSpentFuel(reportUtils.calculateFuel(first, last)); long durationMilliseconds; - if (firstPosition.hasAttribute(Position.KEY_HOURS) && previousPosition.hasAttribute(Position.KEY_HOURS)) { - durationMilliseconds = - previousPosition.getLong(Position.KEY_HOURS) - firstPosition.getLong(Position.KEY_HOURS); + if (first.hasAttribute(Position.KEY_HOURS) && last.hasAttribute(Position.KEY_HOURS)) { + durationMilliseconds = last.getLong(Position.KEY_HOURS) - first.getLong(Position.KEY_HOURS); result.setEngineHours(durationMilliseconds); } else { - durationMilliseconds = - previousPosition.getFixTime().getTime() - firstPosition.getFixTime().getTime(); + durationMilliseconds = last.getFixTime().getTime() - first.getFixTime().getTime(); } if (durationMilliseconds > 0) { - result.setAverageSpeed( - UnitsConverter.knotsFromMps(result.getDistance() * 1000 / durationMilliseconds)); + result.setAverageSpeed(UnitsConverter.knotsFromMps(result.getDistance() * 1000 / durationMilliseconds)); } if (!ignoreOdometer - && firstPosition.getDouble(Position.KEY_ODOMETER) != 0 - && previousPosition.getDouble(Position.KEY_ODOMETER) != 0) { - result.setStartOdometer(firstPosition.getDouble(Position.KEY_ODOMETER)); - result.setEndOdometer(previousPosition.getDouble(Position.KEY_ODOMETER)); + && first.getDouble(Position.KEY_ODOMETER) != 0 && last.getDouble(Position.KEY_ODOMETER) != 0) { + result.setStartOdometer(first.getDouble(Position.KEY_ODOMETER)); + result.setEndOdometer(last.getDouble(Position.KEY_ODOMETER)); } else { - result.setStartOdometer(firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE)); - result.setEndOdometer(previousPosition.getDouble(Position.KEY_TOTAL_DISTANCE)); + result.setStartOdometer(first.getDouble(Position.KEY_TOTAL_DISTANCE)); + result.setEndOdometer(last.getDouble(Position.KEY_TOTAL_DISTANCE)); } - result.setStartTime(firstPosition.getFixTime()); - result.setEndTime(previousPosition.getFixTime()); + result.setStartTime(first.getFixTime()); + result.setEndTime(last.getFixTime()); + return List.of(result); } - return result; - } - private int getDay(long userId, Date date) throws StorageException { - Calendar calendar = Calendar.getInstance(UserUtil.getTimezone( - permissionsService.getServer(), permissionsService.getUser(userId))); - calendar.setTime(date); - return calendar.get(Calendar.DAY_OF_MONTH); + return List.of(); } - private Collection calculateSummaryResults( - long userId, Device device, Date from, Date to, boolean daily) throws StorageException { + private Collection calculateDeviceResults( + Device device, ZonedDateTime from, ZonedDateTime to, boolean daily) throws StorageException { - var positions = PositionUtil.getPositions(storage, device.getId(), from, to); + boolean fast = Duration.between(from, to).toSeconds() > config.getLong(Keys.REPORT_FAST_THRESHOLD); var results = new ArrayList(); - if (daily && !positions.isEmpty()) { - int startIndex = 0; - int startDay = getDay(userId, positions.iterator().next().getFixTime()); - for (int i = 0; i < positions.size(); i++) { - int currentDay = getDay(userId, positions.get(i).getFixTime()); - if (currentDay != startDay) { - results.add(calculateSummaryResult(device, positions.subList(startIndex, i))); - startIndex = i; - startDay = currentDay; - } + if (daily) { + while (from.truncatedTo(ChronoUnit.DAYS).isBefore(to.truncatedTo(ChronoUnit.DAYS))) { + ZonedDateTime fromDay = from.truncatedTo(ChronoUnit.DAYS); + ZonedDateTime nextDay = fromDay.plus(1, ChronoUnit.DAYS); + results.addAll(calculateDeviceResult( + device, Date.from(from.toInstant()), Date.from(nextDay.toInstant()), fast)); + from = nextDay; } - results.add(calculateSummaryResult(device, positions.subList(startIndex, positions.size()))); + results.addAll(calculateDeviceResult(device, Date.from(from.toInstant()), Date.from(to.toInstant()), fast)); } else { - results.add(calculateSummaryResult(device, positions)); + results.addAll(calculateDeviceResult(device, Date.from(from.toInstant()), Date.from(to.toInstant()), fast)); } - return results; } public Collection getObjects( - long userId, Collection deviceIds, - Collection groupIds, Date from, Date to, boolean daily) throws StorageException { + long userId, Collection deviceIds, Collection groupIds, + Date from, Date to, boolean daily) throws StorageException { reportUtils.checkPeriodLimit(from, to); + var tz = UserUtil.getTimezone(permissionsService.getServer(), permissionsService.getUser(userId)).toZoneId(); + ArrayList result = new ArrayList<>(); for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { - Collection deviceResults = calculateSummaryResults(userId, device, from, to, daily); + var deviceResults = calculateDeviceResults( + device, from.toInstant().atZone(tz), to.toInstant().atZone(tz), daily); for (SummaryReportItem summaryReport : deviceResults) { if (summaryReport.getStartTime() != null && summaryReport.getEndTime() != null) { result.add(summaryReport); -- cgit v1.2.3 From cd1ce7c3e89d12f59339ccd2676d7c2bfc1596cf Mon Sep 17 00:00:00 2001 From: geduxas Date: Wed, 24 May 2023 12:47:20 +0300 Subject: Update TeltonikaProtocolDecoder.java Add some IO for FMBxx devices, most of them from lvcan addapter. --- .../traccar/protocol/TeltonikaProtocolDecoder.java | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 2f378f30a..ab127bb95 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -247,7 +247,16 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } }); register(80, fmbXXX, (p, b) -> p.set("dataMode", b.readUnsignedByte())); + register(81, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_SPEED, b.readUnsignedByte())); + register(82, fmbXXX, (p, b) -> p.set(Position.KEY_THROTTLE, b.readUnsignedByte())); + register(83, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_USED, b.readUnsignedInt() * 0.1)); + register(84, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_LEVEL, b.readUnsignedShort() * 0.1)); + register(85, fmbXXX, (p, b) -> p.set(Position.KEY_RPM, b.readUnsignedShort())); + register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt() * 0.001)); + register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); + register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); + register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); 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)); @@ -256,12 +265,28 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(200, fmbXXX, (p, b) -> p.set("sleepMode", b.readUnsignedByte())); register(205, fmbXXX, (p, b) -> p.set("cid2g", b.readUnsignedShort())); register(206, fmbXXX, (p, b) -> p.set("lac", b.readUnsignedShort())); + register(232, fmbXXX, (p, b) -> p.set("cngStatus", b.readUnsignedByte() > 0)); + register(233, fmbXXX, (p, b) -> p.set("cngUsed", b.readUnsignedInt() * 0.1)); + register(234, fmbXXX, (p, b) -> p.set("cngLevel", b.readUnsignedShort())); + register(235, fmbXXX, (p, b) -> p.set("oilLevel", b.readUnsignedByte())); register(236, null, (p, b) -> { p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null); }); register(239, null, (p, b) -> p.set(Position.KEY_IGNITION, b.readUnsignedByte() > 0)); register(240, null, (p, b) -> p.set(Position.KEY_MOTION, b.readUnsignedByte() > 0)); register(241, null, (p, b) -> p.set(Position.KEY_OPERATOR, b.readUnsignedInt())); + register(246, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_TOW : null); + }); + register(247, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_ACCIDENT : null); + }); + register(249, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_JAMMING : null); + }); + register(252, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_POWER_CUT : null); + }); register(253, null, (p, b) -> { switch (b.readUnsignedByte()) { case 1: -- cgit v1.2.3 From 878a66576bcf3700a24ebe9142a09276064b7870 Mon Sep 17 00:00:00 2001 From: geduxas Date: Wed, 24 May 2023 18:29:05 +0300 Subject: Update TeltonikaProtocolDecoder.java Removed duplicate --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index ab127bb95..70d633e19 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -255,7 +255,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt() * 0.001)); register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); - register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); 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)); -- cgit v1.2.3 From 11bbfb69360937c361b701065cdbc2e90699693e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 24 May 2023 15:17:38 -0700 Subject: Remove duplicated list --- src/main/java/org/traccar/reports/common/ReportUtils.java | 11 +++++------ src/test/java/org/traccar/reports/ReportUtilsTest.java | 10 +++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index f5aa6d040..cd52b5de4 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -162,7 +162,7 @@ public class ReportUtils { } private TripReportItem calculateTrip( - Device device, ArrayList positions, int startIndex, int endIndex, + Device device, List positions, int startIndex, int endIndex, boolean ignoreOdometer) throws StorageException { Position startTrip = positions.get(startIndex); @@ -228,7 +228,7 @@ public class ReportUtils { } private StopReportItem calculateStop( - Device device, ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer) { + Device device, List positions, int startIndex, int endIndex, boolean ignoreOdometer) { Position startStop = positions.get(startIndex); Position endStop = positions.get(endIndex); @@ -275,7 +275,7 @@ public class ReportUtils { @SuppressWarnings("unchecked") private T calculateTripOrStop( - Device device, ArrayList positions, int startIndex, int endIndex, + Device device, List positions, int startIndex, int endIndex, boolean ignoreOdometer, Class reportClass) throws StorageException { if (reportClass.equals(TripReportItem.class)) { @@ -285,7 +285,7 @@ public class ReportUtils { } } - private boolean isMoving(ArrayList positions, int index, TripsConfig tripsConfig) { + private boolean isMoving(List positions, int index, TripsConfig tripsConfig) { if (tripsConfig.getMinimalNoDataDuration() > 0) { boolean beforeGap = index < positions.size() - 1 && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime() @@ -301,14 +301,13 @@ public class ReportUtils { } public Collection detectTripsAndStops( - Device device, Collection positionCollection, boolean ignoreOdometer, + Device device, List positions, boolean ignoreOdometer, Class reportClass) throws StorageException { Collection result = new ArrayList<>(); TripsConfig tripsConfig = new TripsConfig( new AttributeUtil.StorageProvider(config, storage, permissionsService, device)); - ArrayList positions = new ArrayList<>(positionCollection); if (!positions.isEmpty()) { boolean trips = reportClass.equals(TripReportItem.class); diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index 22d70c93a..afb0a516f 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -281,7 +281,7 @@ public class ReportUtilsTest extends BaseTest { @Test public void testDetectStopsOnly() throws Exception { - Collection data = Arrays.asList( + var data = Arrays.asList( position("2016-01-01 00:00:00.000", 0, 0), position("2016-01-01 00:01:00.000", 0, 0), position("2016-01-01 00:02:00.000", 1, 0), @@ -309,7 +309,7 @@ public class ReportUtilsTest extends BaseTest { @Test public void testDetectStopsWithTripCut() throws Exception { - Collection data = Arrays.asList( + var data = Arrays.asList( position("2016-01-01 00:00:00.000", 0, 0), position("2016-01-01 00:01:00.000", 0, 0), position("2016-01-01 00:02:00.000", 0, 0), @@ -337,7 +337,7 @@ public class ReportUtilsTest extends BaseTest { @Test public void testDetectStopsStartedFromTrip() throws Exception { - Collection data = Arrays.asList( + var data = Arrays.asList( position("2016-01-01 00:00:00.000", 2, 0), position("2016-01-01 00:01:00.000", 1, 0), position("2016-01-01 00:02:00.000", 0, 0), @@ -365,7 +365,7 @@ public class ReportUtilsTest extends BaseTest { @Test public void testDetectStopsMoving() throws Exception { - Collection data = Arrays.asList( + var data = Arrays.asList( position("2016-01-01 00:00:00.000", 5, 0), position("2016-01-01 00:01:00.000", 5, 0), position("2016-01-01 00:02:00.000", 3, 0), @@ -387,7 +387,7 @@ public class ReportUtilsTest extends BaseTest { @Test public void testDetectTripAndStopByGap() throws Exception { - Collection data = Arrays.asList( + var data = Arrays.asList( position("2016-01-01 00:00:00.000", 7, 100), position("2016-01-01 00:01:00.000", 7, 300), position("2016-01-01 00:02:00.000", 5, 500), -- cgit v1.2.3 From d304c74cfc870d23718cb7aabfd6038492aade8b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 24 May 2023 15:23:53 -0700 Subject: Simplify trips and stops --- .../org/traccar/reports/common/ReportUtils.java | 31 ++++++++-------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index cd52b5de4..6c2d5cd72 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -162,19 +162,7 @@ public class ReportUtils { } private TripReportItem calculateTrip( - Device device, List positions, int startIndex, int endIndex, - boolean ignoreOdometer) throws StorageException { - - Position startTrip = positions.get(startIndex); - Position endTrip = positions.get(endIndex); - - double speedMax = 0; - for (int i = startIndex; i <= endIndex; i++) { - double speed = positions.get(i).getSpeed(); - if (speed > speedMax) { - speedMax = speed; - } - } + Device device, Position startTrip, Position endTrip, boolean ignoreOdometer) throws StorageException { TripReportItem trip = new TripReportItem(); @@ -208,7 +196,6 @@ public class ReportUtils { if (tripDuration > 0) { trip.setAverageSpeed(UnitsConverter.knotsFromMps(trip.getDistance() * 1000 / tripDuration)); } - trip.setMaxSpeed(speedMax); trip.setSpentFuel(calculateFuel(startTrip, endTrip)); trip.setDriverUniqueId(findDriver(startTrip, endTrip)); @@ -228,10 +215,7 @@ public class ReportUtils { } private StopReportItem calculateStop( - Device device, List positions, int startIndex, int endIndex, boolean ignoreOdometer) { - - Position startStop = positions.get(startIndex); - Position endStop = positions.get(endIndex); + Device device, Position startStop, Position endStop, boolean ignoreOdometer) { StopReportItem stop = new StopReportItem(); @@ -279,9 +263,16 @@ public class ReportUtils { boolean ignoreOdometer, Class reportClass) throws StorageException { if (reportClass.equals(TripReportItem.class)) { - return (T) calculateTrip(device, positions, startIndex, endIndex, ignoreOdometer); + var result = calculateTrip(device, positions.get(startIndex), positions.get(endIndex), ignoreOdometer); + for (int i = startIndex; i <= endIndex; i++) { + double speed = positions.get(i).getSpeed(); + if (speed > result.getMaxSpeed()) { + result.setMaxSpeed(speed); + } + } + return (T) result; } else { - return (T) calculateStop(device, positions, startIndex, endIndex, ignoreOdometer); + return (T) calculateStop(device, positions.get(startIndex), positions.get(endIndex), ignoreOdometer); } } -- cgit v1.2.3 From 886efe231e79255aa86a0056e7bf912fff6069fb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 24 May 2023 15:37:04 -0700 Subject: Query positions in report utils --- .../org/traccar/reports/StopsReportProvider.java | 11 ++---- .../org/traccar/reports/TripsReportProvider.java | 11 ++---- .../org/traccar/reports/common/ReportUtils.java | 10 +++--- .../java/org/traccar/reports/ReportUtilsTest.java | 39 +++++++++++++--------- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index a23cee48b..57c57079d 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -20,7 +20,6 @@ import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.model.DeviceUtil; -import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.common.ReportUtils; @@ -56,12 +55,6 @@ public class StopsReportProvider { this.storage = storage; } - private Collection detectStops(Device device, Date from, Date to) throws StorageException { - boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER); - var positions = PositionUtil.getPositions(storage, device.getId(), from, to); - return reportUtils.detectTripsAndStops(device, positions, ignoreOdometer, StopReportItem.class); - } - public Collection getObjects( long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException { @@ -69,7 +62,7 @@ public class StopsReportProvider { ArrayList result = new ArrayList<>(); for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { - result.addAll(detectStops(device, from, to)); + result.addAll(reportUtils.detectTripsAndStops(device, from, to, StopReportItem.class)); } return result; } @@ -82,7 +75,7 @@ public class StopsReportProvider { ArrayList devicesStops = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { - Collection stops = detectStops(device, from, to); + Collection stops = reportUtils.detectTripsAndStops(device, from, to, StopReportItem.class); DeviceReportSection deviceStops = new DeviceReportSection(); deviceStops.setDeviceName(device.getName()); sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName())); diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index 2d8989b7a..e6c3e7ffd 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -20,7 +20,6 @@ import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.model.DeviceUtil; -import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.common.ReportUtils; @@ -56,12 +55,6 @@ public class TripsReportProvider { this.storage = storage; } - private Collection detectTrips(Device device, Date from, Date to) throws StorageException { - boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER); - var positions = PositionUtil.getPositions(storage, device.getId(), from, to); - return reportUtils.detectTripsAndStops(device, positions, ignoreOdometer, TripReportItem.class); - } - public Collection getObjects( long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException { @@ -69,7 +62,7 @@ public class TripsReportProvider { ArrayList result = new ArrayList<>(); for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { - result.addAll(detectTrips(device, from, to)); + result.addAll(reportUtils.detectTripsAndStops(device, from, to, TripReportItem.class)); } return result; } @@ -82,7 +75,7 @@ public class TripsReportProvider { ArrayList devicesTrips = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) { - Collection trips = detectTrips(device, from, to); + Collection trips = reportUtils.detectTripsAndStops(device, from, to, TripReportItem.class); DeviceReportSection deviceTrips = new DeviceReportSection(); deviceTrips.setDeviceName(device.getName()); sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName())); diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 6c2d5cd72..a930f9439 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -58,7 +58,6 @@ import java.io.OutputStream; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; -import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; @@ -291,14 +290,15 @@ public class ReportUtils { return positions.get(index).getBoolean(Position.KEY_MOTION); } - public Collection detectTripsAndStops( - Device device, List positions, boolean ignoreOdometer, - Class reportClass) throws StorageException { + public List detectTripsAndStops( + Device device, Date from, Date to, Class reportClass) throws StorageException { - Collection result = new ArrayList<>(); + List result = new ArrayList<>(); TripsConfig tripsConfig = new TripsConfig( new AttributeUtil.StorageProvider(config, storage, permissionsService, device)); + boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER); + var positions = PositionUtil.getPositions(storage, device.getId(), from, to); if (!positions.isEmpty()) { boolean trips = reportClass.equals(TripReportItem.class); diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index afb0a516f..d11d2b2e1 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -2,7 +2,6 @@ package org.traccar.reports; import org.apache.velocity.app.VelocityEngine; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.traccar.BaseTest; import org.traccar.api.security.PermissionsService; @@ -21,7 +20,6 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; -import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -33,6 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -43,7 +42,7 @@ public class ReportUtilsTest extends BaseTest { @BeforeEach public void init() throws StorageException { storage = mock(Storage.class); - when(storage.getObject(any(), any())).thenReturn(mock(Device.class)); + when(storage.getObject(eq(Device.class), any())).thenReturn(mock(Device.class)); } private Date date(String time) throws ParseException { @@ -114,12 +113,13 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:05:00.000", 0, 3000), position("2016-01-01 00:15:00.000", 0, 3000), position("2016-01-01 00:25:00.000", 0, 3000)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); Device device = mockDevice(500, 300, 180, 900, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -133,7 +133,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -166,6 +166,7 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:05:00.000", 0, 3000), position("2016-01-01 00:15:00.000", 0, 3000), position("2016-01-01 00:25:00.000", 0, 3000)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); data.get(5).set(Position.KEY_IGNITION, false); @@ -173,7 +174,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -187,7 +188,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); + trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -201,7 +202,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -238,12 +239,13 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:09:00.000", 0, 7000), position("2016-01-01 00:19:00.000", 0, 7000), position("2016-01-01 00:29:00.000", 0, 7000)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); Device device = mockDevice(500, 300, 180, 900, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -257,7 +259,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(7000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -288,12 +290,13 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:03:00.000", 0, 0), position("2016-01-01 00:04:00.000", 1, 0), position("2016-01-01 00:05:00.000", 0, 0)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -316,12 +319,13 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:03:00.000", 0, 0), position("2016-01-01 00:04:00.000", 1, 0), position("2016-01-01 00:05:00.000", 2, 0)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -344,12 +348,13 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:12:00.000", 0, 0), position("2016-01-01 00:22:00.000", 0, 0), position("2016-01-01 00:32:00.000", 0, 0)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -372,12 +377,13 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:03:00.000", 5, 0), position("2016-01-01 00:04:00.000", 5, 0), position("2016-01-01 00:05:00.000", 5, 0)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); Device device = mockDevice(500, 300, 200, 900, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertTrue(result.isEmpty()); @@ -396,12 +402,13 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:23:00.000", 2, 700), position("2016-01-01 00:24:00.000", 5, 800), position("2016-01-01 00:25:00.000", 5, 900)); + when(storage.getObjects(eq(Position.class), any())).thenReturn(data); Device device = mockDevice(500, 200, 200, 900, false); ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, data, false, TripReportItem.class); + var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -415,7 +422,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(7, itemTrip.getMaxSpeed(), 0.01); assertEquals(600, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, data, false, StopReportItem.class); + var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); -- cgit v1.2.3 From 81b3df465cefa6a6aa25334d79c7a2509dfb26d0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 24 May 2023 17:11:04 -0700 Subject: Add fast trips and stops --- .../org/traccar/reports/common/ReportUtils.java | 83 ++++++++++++++++++---- .../java/org/traccar/reports/ReportUtilsTest.java | 26 +++---- 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index a930f9439..28e3d2ae5 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -37,6 +37,7 @@ import org.traccar.helper.model.UserUtil; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Driver; +import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.reports.model.BaseReportItem; @@ -48,6 +49,7 @@ import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; import javax.annotation.Nullable; @@ -57,10 +59,13 @@ import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.Duration; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; public class ReportUtils { @@ -161,7 +166,8 @@ public class ReportUtils { } private TripReportItem calculateTrip( - Device device, Position startTrip, Position endTrip, boolean ignoreOdometer) throws StorageException { + Device device, Position startTrip, Position endTrip, double maxSpeed, + boolean ignoreOdometer) throws StorageException { TripReportItem trip = new TripReportItem(); @@ -195,6 +201,7 @@ public class ReportUtils { if (tripDuration > 0) { trip.setAverageSpeed(UnitsConverter.knotsFromMps(trip.getDistance() * 1000 / tripDuration)); } + trip.setMaxSpeed(maxSpeed); trip.setSpentFuel(calculateFuel(startTrip, endTrip)); trip.setDriverUniqueId(findDriver(startTrip, endTrip)); @@ -258,20 +265,13 @@ public class ReportUtils { @SuppressWarnings("unchecked") private T calculateTripOrStop( - Device device, List positions, int startIndex, int endIndex, + Device device, Position startPosition, Position endPosition, double maxSpeed, boolean ignoreOdometer, Class reportClass) throws StorageException { if (reportClass.equals(TripReportItem.class)) { - var result = calculateTrip(device, positions.get(startIndex), positions.get(endIndex), ignoreOdometer); - for (int i = startIndex; i <= endIndex; i++) { - double speed = positions.get(i).getSpeed(); - if (speed > result.getMaxSpeed()) { - result.setMaxSpeed(speed); - } - } - return (T) result; + return (T) calculateTrip(device, startPosition, endPosition, maxSpeed, ignoreOdometer); } else { - return (T) calculateStop(device, positions.get(startIndex), positions.get(endIndex), ignoreOdometer); + return (T) calculateStop(device, startPosition, endPosition, ignoreOdometer); } } @@ -293,6 +293,17 @@ public class ReportUtils { public List detectTripsAndStops( Device device, Date from, Date to, Class reportClass) throws StorageException { + long threshold = config.getLong(Keys.REPORT_FAST_THRESHOLD); + if (Duration.between(from.toInstant(), to.toInstant()).toSeconds() > threshold) { + return fastTripsAndStops(device, from, to, reportClass); + } else { + return slowTripsAndStops(device, from, to, reportClass); + } + } + + public List slowTripsAndStops( + Device device, Date from, Date to, Class reportClass) throws StorageException { + List result = new ArrayList<>(); TripsConfig tripsConfig = new TripsConfig( new AttributeUtil.StorageProvider(config, storage, permissionsService, device)); @@ -308,17 +319,23 @@ public class ReportUtils { motionState.setMotionState(initialValue); boolean detected = trips == motionState.getMotionState(); + double maxSpeed = 0; int startEventIndex = detected ? 0 : -1; int startNoEventIndex = -1; for (int i = 0; i < positions.size(); i++) { boolean motion = isMoving(positions, i, tripsConfig); if (motionState.getMotionState() != motion) { if (motion == trips) { - startEventIndex = detected ? startEventIndex : i; + if (!detected) { + startEventIndex = i; + maxSpeed = positions.get(i).getSpeed(); + } startNoEventIndex = -1; } else { startNoEventIndex = i; } + } else { + maxSpeed = Math.max(maxSpeed, positions.get(i).getSpeed()); } MotionProcessor.updateState(motionState, positions.get(i), motion, tripsConfig); @@ -328,7 +345,8 @@ public class ReportUtils { startNoEventIndex = -1; } else if (startEventIndex >= 0 && startNoEventIndex >= 0) { result.add(calculateTripOrStop( - device, positions, startEventIndex, startNoEventIndex, ignoreOdometer, reportClass)); + device, positions.get(startEventIndex), positions.get(startNoEventIndex), + maxSpeed, ignoreOdometer, reportClass)); detected = false; startEventIndex = -1; startNoEventIndex = -1; @@ -338,7 +356,44 @@ public class ReportUtils { if (detected & startEventIndex >= 0 && startEventIndex < positions.size() - 1) { int endIndex = startNoEventIndex >= 0 ? startNoEventIndex : positions.size() - 1; result.add(calculateTripOrStop( - device, positions, startEventIndex, endIndex, ignoreOdometer, reportClass)); + device, positions.get(startEventIndex), positions.get(endIndex), + maxSpeed, ignoreOdometer, reportClass)); + } + } + + return result; + } + + public List fastTripsAndStops( + Device device, Date from, Date to, Class reportClass) throws StorageException { + + List result = new ArrayList<>(); + boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER); + boolean trips = reportClass.equals(TripReportItem.class); + Set filter = Set.of(Event.TYPE_DEVICE_MOVING, Event.TYPE_DEVICE_STOPPED); + + var events = storage.getObjects(Event.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", device.getId()), + new Condition.Between("eventTime", "from", from, "to", to)), + new Order("eventTime"))); + var filteredEvents = events.stream() + .filter(event -> filter.contains(event.getType())) + .collect(Collectors.toList()); + + Event startEvent = null; + for (Event event : filteredEvents) { + boolean motion = event.getType().equals(Event.TYPE_DEVICE_MOVING); + if (motion == trips) { + startEvent = event; + } else if (startEvent != null) { + Position startPosition = storage.getObject(Position.class, new Request( + new Columns.All(), new Condition.Equals("id", startEvent.getPositionId()))); + Position endPosition = storage.getObject(Position.class, new Request( + new Columns.All(), new Condition.Equals("id", event.getPositionId()))); + result.add(calculateTripOrStop(device, startPosition, endPosition, 0, ignoreOdometer, reportClass)); + startEvent = null; } } diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index d11d2b2e1..0f14577fd 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -119,7 +119,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); + var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -133,7 +133,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -174,7 +174,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); + var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -188,7 +188,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); + trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -202,7 +202,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -245,7 +245,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); + var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -259,7 +259,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(7000, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -296,7 +296,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -325,7 +325,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -354,7 +354,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -383,7 +383,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var result = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(result); assertTrue(result.isEmpty()); @@ -408,7 +408,7 @@ public class ReportUtilsTest extends BaseTest { ReportUtils reportUtils = new ReportUtils( mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null); - var trips = reportUtils.detectTripsAndStops(device, new Date(), new Date(), TripReportItem.class); + var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -422,7 +422,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(7, itemTrip.getMaxSpeed(), 0.01); assertEquals(600, itemTrip.getDistance(), 0.01); - var stops = reportUtils.detectTripsAndStops(device, new Date(), new Date(), StopReportItem.class); + var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); -- cgit v1.2.3 From dee954b9f28c129215e9fa600e6860e2d4adb673 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 25 May 2023 06:48:50 -0700 Subject: Remove status event links --- templates/full/deviceOffline.vm | 1 - templates/full/deviceOnline.vm | 1 - templates/full/deviceUnknown.vm | 1 - 3 files changed, 3 deletions(-) diff --git a/templates/full/deviceOffline.vm b/templates/full/deviceOffline.vm index 8f2c515b2..6d2122624 100644 --- a/templates/full/deviceOffline.vm +++ b/templates/full/deviceOffline.vm @@ -5,7 +5,6 @@ Device: $device.name
Offline
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
-Link: $webUrl?eventId=$event.id

Unsubscribe diff --git a/templates/full/deviceOnline.vm b/templates/full/deviceOnline.vm index 81a4ccbc8..02260c4fb 100644 --- a/templates/full/deviceOnline.vm +++ b/templates/full/deviceOnline.vm @@ -5,7 +5,6 @@ Device: $device.name
Online
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
-Link: $webUrl?eventId=$event.id

Unsubscribe diff --git a/templates/full/deviceUnknown.vm b/templates/full/deviceUnknown.vm index e012845e6..e99981069 100644 --- a/templates/full/deviceUnknown.vm +++ b/templates/full/deviceUnknown.vm @@ -5,7 +5,6 @@ Device: $device.name
Status is unknown
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
-Link: $webUrl?eventId=$event.id

Unsubscribe -- cgit v1.2.3 From 86511cd68d968c15db66ddfbe831a34be13e8ba1 Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Thu, 25 May 2023 19:58:07 -0400 Subject: Acknowledge mileage alert and decode third input status --- .../traccar/protocol/LaipacProtocolDecoder.java | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index e9570ee11..ede4650b8 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -110,17 +110,25 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private String decodeEvent(String event, Position position) { - if (event.length() == 1) { - char inputStatus = event.charAt(0); - if (inputStatus >= 'A' && inputStatus <= 'D') { - int inputStatusInt = inputStatus - 'A'; - position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); - position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); - return null; - } + if (event.length() != 1) + return event; + + int inputStatusInt = 0; + char inputStatus = event.charAt(0); + + if (inputStatus >= 'A' && inputStatus <= 'D') { + inputStatusInt = inputStatus - 'A'; + } else if(inputStatus >= 'O' && inputStatus <= 'R') { + inputStatusInt = inputStatus - 'O' + 4; + } else { + return event; } - return event; + position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); + position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + position.set(Position.PREFIX_IN + 3, inputStatusInt & 4); + + return null; } private void sendEventResponse( @@ -132,6 +140,9 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { case "3": responseCode = "d"; break; + case "M": + responseCode = "m"; + break; case "S": case "T": responseCode = "t"; -- cgit v1.2.3 From 03b9409f05c2edef2c1f52dde8bedc2f43184a50 Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Thu, 25 May 2023 20:03:35 -0400 Subject: Fix style check violation --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index ede4650b8..5b9629ff3 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -118,7 +118,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { if (inputStatus >= 'A' && inputStatus <= 'D') { inputStatusInt = inputStatus - 'A'; - } else if(inputStatus >= 'O' && inputStatus <= 'R') { + } else if (inputStatus >= 'O' && inputStatus <= 'R') { inputStatusInt = inputStatus - 'O' + 4; } else { return event; -- cgit v1.2.3 From 6c3b33275e2d8310011c38ed1bc292546e15cae9 Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Thu, 25 May 2023 20:06:59 -0400 Subject: Fix style check violation --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 5b9629ff3..3b654db0c 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -110,8 +110,9 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private String decodeEvent(String event, Position position) { - if (event.length() != 1) + if (event.length() != 1) { return event; + } int inputStatusInt = 0; char inputStatus = event.charAt(0); -- cgit v1.2.3 From 6cc15fb06c9490e349847e043eea7c188e88794e Mon Sep 17 00:00:00 2001 From: merabtenei Date: Sun, 28 May 2023 21:38:14 +0100 Subject: fix NullPointerException when attribute key is defined and value is set to null, caused by calling .toString() on null. --- src/main/java/org/traccar/model/ExtendedModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java index 6a4f502f7..d3d247fdd 100644 --- a/src/main/java/org/traccar/model/ExtendedModel.java +++ b/src/main/java/org/traccar/model/ExtendedModel.java @@ -90,7 +90,7 @@ public class ExtendedModel extends BaseModel { } public String getString(String key, String defaultValue) { - if (attributes.containsKey(key)) { + if (attributes.containsKey(key) && attributes.get(key) != null) { return attributes.get(key).toString(); } else { return defaultValue; -- cgit v1.2.3 From 729df52ea52ce5807b6328eb04cf55d3e9cbea81 Mon Sep 17 00:00:00 2001 From: merabtenei Date: Sun, 28 May 2023 21:56:55 +0100 Subject: do not add permission if user is serviceAccount --- src/main/java/org/traccar/api/BaseObjectResource.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 904781e54..b007b7bcd 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -16,6 +16,7 @@ */ package org.traccar.api; +import org.traccar.api.security.ServiceAccountUser; import org.traccar.helper.LogAction; import org.traccar.model.BaseModel; import org.traccar.model.Group; @@ -70,10 +71,13 @@ public abstract class BaseObjectResource extends BaseResour entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); LogAction.create(getUserId(), entity); - storage.addPermission(new Permission(User.class, getUserId(), baseClass, entity.getId())); - cacheManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId()); - connectionManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId()); - LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId()); + + if (getUserId() != ServiceAccountUser.ID) { + storage.addPermission(new Permission(User.class, getUserId(), baseClass, entity.getId())); + cacheManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId()); + connectionManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId()); + LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId()); + } return Response.ok(entity).build(); } -- cgit v1.2.3 From 671e8fbdfd90dce91f372750105561fa7d3b472c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 28 May 2023 17:54:08 -0700 Subject: Change default timeout --- src/main/java/org/traccar/config/Keys.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 8246fdeac..d4780ba46 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -761,12 +761,12 @@ public final class Keys { List.of(KeyType.CONFIG)); /** - * WebSocket connection timeout in milliseconds. Default timeout is 10 minutes. + * WebSocket connection timeout in milliseconds. Default timeout is 5 minutes. */ public static final ConfigKey WEB_TIMEOUT = new LongConfigKey( "web.timeout", List.of(KeyType.CONFIG), - 60000L); + 300000L); /** * Authentication sessions timeout in seconds. By default no timeout. -- cgit v1.2.3 From ef3088a09c42e518fe9c6a313b9c15523adb8b15 Mon Sep 17 00:00:00 2001 From: "I. MERABTENE" <95150308+merabtenei@users.noreply.github.com> Date: Mon, 29 May 2023 10:35:28 +0100 Subject: Update src/main/java/org/traccar/model/ExtendedModel.java Co-authored-by: Anton Tananaev --- src/main/java/org/traccar/model/ExtendedModel.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java index d3d247fdd..9da9c7529 100644 --- a/src/main/java/org/traccar/model/ExtendedModel.java +++ b/src/main/java/org/traccar/model/ExtendedModel.java @@ -90,8 +90,9 @@ public class ExtendedModel extends BaseModel { } public String getString(String key, String defaultValue) { - if (attributes.containsKey(key) && attributes.get(key) != null) { - return attributes.get(key).toString(); + if (attributes.containsKey(key)) { + Object value = attributes.get(key); + return value != null ? value.toString() : value; } else { return defaultValue; } -- cgit v1.2.3 From 46dabfabdc7b6cc12cbad9863e38ab1ff97c40a5 Mon Sep 17 00:00:00 2001 From: merabtenei Date: Mon, 29 May 2023 16:03:12 +0100 Subject: fix return null value --- src/main/java/org/traccar/model/ExtendedModel.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java index d3d247fdd..0a0923ba1 100644 --- a/src/main/java/org/traccar/model/ExtendedModel.java +++ b/src/main/java/org/traccar/model/ExtendedModel.java @@ -90,8 +90,9 @@ public class ExtendedModel extends BaseModel { } public String getString(String key, String defaultValue) { - if (attributes.containsKey(key) && attributes.get(key) != null) { - return attributes.get(key).toString(); + if (attributes.containsKey(key)) { + Object value = attributes.containsKey(key); + return value != null ? value.toString() : null; } else { return defaultValue; } -- cgit v1.2.3 From d244b4bc4999ba3e3dca607bf797c3f7d7f578ff Mon Sep 17 00:00:00 2001 From: merabtenei Date: Mon, 29 May 2023 18:07:31 +0100 Subject: fix typo: replaced .containsKey with .get --- src/main/java/org/traccar/model/ExtendedModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java index 0a0923ba1..d5cd094da 100644 --- a/src/main/java/org/traccar/model/ExtendedModel.java +++ b/src/main/java/org/traccar/model/ExtendedModel.java @@ -91,7 +91,7 @@ public class ExtendedModel extends BaseModel { public String getString(String key, String defaultValue) { if (attributes.containsKey(key)) { - Object value = attributes.containsKey(key); + Object value = attributes.get(key); return value != null ? value.toString() : null; } else { return defaultValue; -- cgit v1.2.3 From 4cf820b3dd4d8686842d36c81ee8ee3e954b2393 Mon Sep 17 00:00:00 2001 From: merabtenei Date: Mon, 29 May 2023 21:46:54 +0100 Subject: added Battery Level as IO 113 in TeltonikaProtocolDecoder.java --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 70d633e19..c6531c790 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -256,6 +256,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); + register(113, fmbXXX, (p, b) -> p.set(Position.KEY_BATTERY_LEVEL, b.readUnsignedByte())); 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)); -- cgit v1.2.3 From 854afb13bd8115a17b9c6c4cf739707313a709cf Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 May 2023 10:39:21 -0700 Subject: Support file uploading --- .../org/traccar/api/resource/ServerResource.java | 36 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index f334b7a21..dcb059b69 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -16,12 +16,14 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; +import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.database.OpenIdProvider; -import org.traccar.helper.model.UserUtil; -import org.traccar.mail.MailManager; import org.traccar.geocoder.Geocoder; import org.traccar.helper.Log; import org.traccar.helper.LogAction; +import org.traccar.helper.model.UserUtil; +import org.traccar.mail.MailManager; import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.session.cache.CacheManager; @@ -36,12 +38,20 @@ import javax.annotation.security.PermitAll; import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Arrays; import java.util.Collection; import java.util.TimeZone; @@ -51,6 +61,9 @@ import java.util.TimeZone; @Consumes(MediaType.APPLICATION_JSON) public class ServerResource extends BaseResource { + @Inject + private Config config; + @Inject private CacheManager cacheManager; @@ -119,4 +132,23 @@ public class ServerResource extends BaseResource { return Arrays.asList(TimeZone.getAvailableIDs()); } + @Path("file/{path}") + @POST + @Consumes("*/*") + public Response uploadImage(@PathParam("path") String path, File inputFile) throws IOException, StorageException { + permissionsService.checkAdmin(getUserId()); + String root = config.getString(Keys.WEB_OVERRIDE, config.getString(Keys.WEB_PATH)); + + var outputPath = Paths.get(root, path); + var directoryPath = outputPath.getParent(); + if (directoryPath != null) { + Files.createDirectories(directoryPath); + } + + try (var input = new FileInputStream(inputFile); var output = new FileOutputStream(outputPath.toFile())) { + input.transferTo(output); + } + return Response.ok().build(); + } + } -- cgit v1.2.3 From 8de9a36abef8e66be4fcc248b49045ffd3b5f7ae Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 May 2023 11:41:03 -0700 Subject: Handle missing GoSafe fields --- .../java/org/traccar/protocol/GoSafeProtocolDecoder.java | 12 ++++++------ .../java/org/traccar/protocol/GoSafeProtocolDecoderTest.java | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java index 77649a041..f17ea0e08 100644 --- a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java @@ -93,14 +93,14 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); } position.setCourse(Integer.parseInt(values[index++])); - if (index < values.length) { - position.setAltitude(Integer.parseInt(values[index++])); + if (index < values.length && !values[index++].isEmpty()) { + position.setAltitude(Integer.parseInt(values[index - 1])); } - if (index < values.length) { - position.set(Position.KEY_HDOP, Double.parseDouble(values[index++])); + if (index < values.length && !values[index++].isEmpty()) { + position.set(Position.KEY_HDOP, Double.parseDouble(values[index - 1])); } - if (index < values.length) { - position.set(Position.KEY_VDOP, Double.parseDouble(values[index++])); + if (index < values.length && !values[index++].isEmpty()) { + position.set(Position.KEY_VDOP, Double.parseDouble(values[index - 1])); } break; case "GSM": diff --git a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java index ad944d73a..3e1349a80 100644 --- a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java @@ -14,6 +14,9 @@ public class GoSafeProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, false, text( "*GS06,357330050846344,RST#")); + verifyPositions(decoder, text( + "*GS06,353218073585128,181255300523,,SYS:Smart Track;V9.31;V1.1.5,GPS:A;5;N31.551856;E74.366920;0;0;;2.15;2.64,COT:0,ADC:10.78;0.02,DTT:4002;E1;0;0;0;1$181325300523,,SYS:Smart Track;V9.31;V1.1.5,GPS:A;6;N31.551856;E74.366920;0;0;;2.05;2.13,COT:0,ADC:10.79;0.02,DTT:4002;E1;0;0;0;1#")); + verifyAttribute(decoder, text( "*GS06,356449068350122,013519070819,,SYS:G6S;V3.37;V1.1.8,GPS:A;12;N23.169866;E113.450728;0;255;54;0.79,COT:18779;,ADC:12.66;0.58,DTT:4084;E1;0;0;0;1,IWD:0;1;ad031652643fff28;23.2;1;1;86031652504fff28;24.3;2;1;e603165252a5ff28;24.2;3;1;bb0416557da6ff28;24.0#"), Position.PREFIX_TEMP + 3, 24.0); -- cgit v1.2.3 From 59994e07fa109bdb7a80c6ce2c480049012b8db5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 May 2023 12:02:15 -0700 Subject: Update Java dependencies --- build.gradle | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 1fa3986fd..9dba72db2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ plugins { id "java" id "checkstyle" - id "com.google.protobuf" version "0.8.19" - id "org.kordamp.gradle.project-enforcer" version "0.10.0" + id "com.google.protobuf" version "0.9.3" + id "org.kordamp.gradle.project-enforcer" version "0.13.0" } repositories { @@ -14,7 +14,7 @@ compileJava.options.encoding = "UTF-8" jar.destinationDirectory = file("$projectDir/target") checkstyle { - toolVersion = "10.3.4" + toolVersion = "10.12.0" configFile = "gradle/checkstyle.xml" as File checkstyleTest.enabled = false } @@ -26,13 +26,13 @@ enforce { } ext { - guiceVersion = "5.1.0" + guiceVersion = "6.0.0" jettyVersion = "10.0.15" // jetty 11 javax to jakarta jerseyVersion = "2.39.1" // jersey 3 javax to jakarta jacksonVersion = "2.14.1" // same version as jersey-media-json-jackson dependency - protobufVersion = "3.22.3" + protobufVersion = "3.23.2" jxlsVersion = "2.12.0" - junitVersion = "5.9.2" + junitVersion = "5.9.3" } protobuf { @@ -44,11 +44,11 @@ protobuf { dependencies { implementation "commons-codec:commons-codec:1.15" implementation "com.h2database:h2:2.1.214" - implementation "com.mysql:mysql-connector-j:8.0.32" + implementation "com.mysql:mysql-connector-j:8.0.33" implementation "org.postgresql:postgresql:42.6.0" implementation "com.microsoft.sqlserver:mssql-jdbc:12.2.0.jre11" implementation "com.zaxxer:HikariCP:5.0.1" - implementation "io.netty:netty-all:4.1.91.Final" + implementation "io.netty:netty-all:4.1.93.Final" implementation "org.slf4j:slf4j-jdk14:2.0.7" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" @@ -67,7 +67,7 @@ dependencies { implementation "org.glassfish.hk2:guice-bridge:2.6.1" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.21.1" + implementation "org.liquibase:liquibase-core:4.22.0" implementation "com.sun.mail:jakarta.mail:1.6.7" implementation "org.apache.commons:commons-jexl3:3.3" implementation "org.jxls:jxls:$jxlsVersion" @@ -82,15 +82,15 @@ dependencies { implementation "com.github.jnr:jnr-posix:3.1.16" implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation "javax.activation:activation:1.1.1" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.450" + implementation "com.amazonaws:aws-java-sdk-sns:1.12.477" implementation "org.apache.kafka:kafka-clients:3.4.0" implementation "com.hivemq:hivemq-mqtt-client:1.3.1" - implementation "redis.clients:jedis:4.3.2" + implementation "redis.clients:jedis:4.4.1" implementation "com.google.firebase:firebase-admin:9.1.1" - implementation "com.nimbusds:oauth2-oidc-sdk:10.7.1" + implementation "com.nimbusds:oauth2-oidc-sdk:10.9.1" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:5.3.0" + testImplementation "org.mockito:mockito-core:5.3.1" } test { -- cgit v1.2.3 From 4b7e7537029b3e3f5f05168f063a4f71b987405b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 May 2023 13:53:23 -0700 Subject: Update version number --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 9dba72db2..727d2342e 100644 --- a/build.gradle +++ b/build.gradle @@ -107,7 +107,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.7", + "Implementation-Version": "5.8", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 821c90958..f9988a6f3 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.7 +AppVersion=5.8 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index 889728d33..eec852ac7 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.7", + "version": "5.8", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From 4d6d6466e9c0abfd8aa06d36189b81cda3107c8e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 May 2023 13:58:30 -0700 Subject: Remove unused class --- .../org/traccar/protocol/NdtpV6FrameDecoder.java | 32 ---------------------- 1 file changed, 32 deletions(-) delete mode 100644 src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java diff --git a/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java b/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java deleted file mode 100644 index 5b610013a..000000000 --- a/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 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.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class NdtpV6FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - return buf; - } - -} -- cgit v1.2.3 From 41d7a5ad4c32d3911d6096802f0339ebe4bc0f39 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 May 2023 14:01:25 -0700 Subject: Add integration test --- tools/test-integration.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/test-integration.py b/tools/test-integration.py index 84d2fa2e3..204fecb70 100755 --- a/tools/test-integration.py +++ b/tools/test-integration.py @@ -126,6 +126,7 @@ messages = { 'armoli': '[M123456789012345210122125205N38.735641E035.4727751E003340000000C00000E9E07FF:106AG505283H60E];', 'teratrack': '{"MDeviceID":"022043756090","DiviceType":"1","DataType":"1","DataLength":"69","DateTime":"2022-03-09 10:56:01","Latitude":"-6.846451","Longitude":"39.316324","LongitudeState":"1","LatitudeState":"0","Speed":"90","Mileage":"0","FenceAlarm":"0","AreaAlarmID":"0","LockCutOff":"0","SealTampered":"0","MessageAck":"1","LockRope":"1","LockStatus":"1","LockOpen":"0","PasswordError":"0","CardNo":"60000644","IllegalCard":"0","LowPower":"0","UnCoverBack":"0","CoverStatus":"1","LockStuck":"0","Power":"79","GSM":"16","IMEI":"123456789012345","Index":"20","Slave":[]}', 'envotech': '$80SLM,02,F,123456,130410155921,431750216,000040,0000,,00000000,\'13041015592110476673N10111459E001281*2A#', + 'bstpl': 'BSTPL$1,123456789012345,V,200722,045113,00.000000,0,00.00000,0,0,0,000,00,0,17,1,1,0,0,00.01,0,04.19,15B_190821,8991000907387031196F,12.27#', } baseUrl = 'http://localhost:8082' -- cgit v1.2.3 From a24d7d5d7a61946b45ed5d344fee0a0e27bd3144 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 May 2023 15:20:46 -0700 Subject: Update submodule --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 74dc5065f..f8048106d 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 74dc5065ffd3866d660fd7b908a26c5089173d08 +Subproject commit f8048106dacb36466ae221a8258da85f35db6e9d -- cgit v1.2.3 From fdbd269b9b99de074e2fd9d99d1702620102801b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 4 Jun 2023 17:59:44 -0700 Subject: Handle decimal temperature --- src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java index 4e5200f37..4d8e7e7ea 100644 --- a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java @@ -153,7 +153,7 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RSSI, Integer.parseInt(value)); break; case 0x82: - position.set(Position.KEY_DEVICE_TEMP, Integer.parseInt(value) * 0.1); + position.set(Position.KEY_DEVICE_TEMP, Double.parseDouble(value) * 0.1); break; case 0x104: position.set(Position.KEY_ENGINE_LOAD, Integer.parseInt(value)); diff --git a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java index dae3815ac..53ed07da7 100644 --- a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class FreematicsProtocolDecoderTest extends ProtocolTest { var decoder = inject(new FreematicsProtocolDecoder(null)); + verifyPositions(decoder, text( + "UCFLFAYM#0:33770,24:300,82:53.000000,*F9")); + verifyPositions(decoder, text( "M0ZR4X0#0:204391,11:140221,10:8445000,A:49.215920,B:18.737755,C:410,D:0,E:208,24:1252,20:0;0;0,82:47*B5")); -- cgit v1.2.3 From 1df3562c439ac8d23c1f03e60acba39468de138c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 5 Jun 2023 19:51:41 -0700 Subject: Handle missing positions (fix #5104) --- src/main/java/org/traccar/reports/common/ReportUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 28e3d2ae5..995e92676 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -392,7 +392,10 @@ public class ReportUtils { new Columns.All(), new Condition.Equals("id", startEvent.getPositionId()))); Position endPosition = storage.getObject(Position.class, new Request( new Columns.All(), new Condition.Equals("id", event.getPositionId()))); - result.add(calculateTripOrStop(device, startPosition, endPosition, 0, ignoreOdometer, reportClass)); + if (startPosition != null && endPosition != null) { + result.add(calculateTripOrStop( + device, startPosition, endPosition, 0, ignoreOdometer, reportClass)); + } startEvent = null; } } -- cgit v1.2.3 From 3c8acbd681409a068f3428ce2cbd8cf002d0b974 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Wed, 7 Jun 2023 02:27:52 +0000 Subject: redis broadcast service --- .../traccar/broadcast/RedisBroadcastService.java | 206 +++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 src/main/java/org/traccar/broadcast/RedisBroadcastService.java diff --git a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java new file mode 100644 index 000000000..a6968c894 --- /dev/null +++ b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java @@ -0,0 +1,206 @@ +/* + * 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.broadcast; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.BaseModel; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Permission; +import org.traccar.model.Position; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +public class RedisBroadcastService implements BroadcastService { + + private static final Logger LOGGER = LoggerFactory.getLogger(RedisBroadcastService.class); + + private final ObjectMapper objectMapper; + + private final ExecutorService service = Executors.newSingleThreadExecutor(); + + private final Set listeners = new HashSet<>(); + + private final String url; + private final String pubsubChannel = "traccar:cast"; + + private final Jedis subscriberJedis; + private final Jedis publisherJedis; + + private final String id; + + public RedisBroadcastService(Config config, ObjectMapper objectMapper) throws IOException { + this.objectMapper = objectMapper; + url = config.getString(Keys.BROADCAST_ADDRESS); + + subscriberJedis = new Jedis(url); + publisherJedis = new Jedis(url); + + // id that will be used to identify this instance of the server + id = String.valueOf(System.currentTimeMillis()); + } + + @Override + public boolean singleInstance() { + return false; + } + + @Override + public void registerListener(BroadcastInterface listener) { + listeners.add(listener); + } + + @Override + public void updateDevice(boolean local, Device device) { + BroadcastMessage message = new BroadcastMessage(); + message.setDevice(device); + sendMessage(message); + } + + @Override + public void updatePosition(boolean local, Position position) { + BroadcastMessage message = new BroadcastMessage(); + message.setPosition(position); + sendMessage(message); + } + + @Override + public void updateEvent(boolean local, long userId, Event event) { + BroadcastMessage message = new BroadcastMessage(); + message.setUserId(userId); + message.setEvent(event); + sendMessage(message); + } + + @Override + public void updateCommand(boolean local, long deviceId) { + BroadcastMessage message = new BroadcastMessage(); + message.setCommandDeviceId(deviceId); + sendMessage(message); + } + + @Override + public void invalidateObject(boolean local, Class clazz, long id) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz), id)); + sendMessage(message); + } + + @Override + public void invalidatePermission( + boolean local, + Class clazz1, long id1, + Class clazz2, long id2) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); + sendMessage(message); + } + + private void sendMessage(BroadcastMessage message) { + try { + String payload = id + ":" + objectMapper.writeValueAsString(message); + publisherJedis.publish(pubsubChannel, payload); + } catch (IOException e) { + LOGGER.warn("Broadcast failed", e); + } + } + + private void handleMessage(BroadcastMessage message) { + if (message.getDevice() != null) { + listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); + } else if (message.getPosition() != null) { + listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); + } else if (message.getUserId() != null && message.getEvent() != null) { + listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); + } else if (message.getCommandDeviceId() != null) { + listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); + } else if (message.getChanges() != null) { + var iterator = message.getChanges().entrySet().iterator(); + if (iterator.hasNext()) { + var first = iterator.next(); + if (iterator.hasNext()) { + var second = iterator.next(); + listeners.forEach(listener -> listener.invalidatePermission( + false, + Permission.getKeyClass(first.getKey()), first.getValue(), + Permission.getKeyClass(second.getKey()), second.getValue())); + } else { + listeners.forEach(listener -> listener.invalidateObject( + false, + Permission.getKeyClass(first.getKey()), first.getValue())); + } + } + } + } + + @Override + public void start() throws IOException { + service.submit(receiver); + } + + @Override + public void stop() { + service.shutdown(); + } + + private final Runnable receiver = new Runnable() { + @Override + public void run() { + subscriberJedis.subscribe(new JedisPubSub() { + @Override + public void onMessage(String channel, String message) { + try { + String[] parts = message.split(":", 2); + if (channel == pubsubChannel && parts.length == 2 && !id.equals(parts[0])) { + handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); + } + } catch (IOException e) { + LOGGER.warn("Broadcast handleMessage failed", e); + } + } + }, pubsubChannel); + + while (!service.isShutdown()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + } + + try { + subscriberJedis.close(); + publisherJedis.close(); + } catch (Exception e) { + LOGGER.warn("Failed to close pubsub", e); + throw new RuntimeException(e); + } + } + }; + +} -- cgit v1.2.3 From cfd91d45b6731e6632ebb8a4913f807bab510707 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Wed, 7 Jun 2023 02:28:53 +0000 Subject: redis broadcast implementation --- src/main/java/org/traccar/MainModule.java | 11 ++++++++++- src/main/java/org/traccar/config/Keys.java | 8 ++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 6a2fe21c3..b1a8006ee 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -28,6 +28,7 @@ import io.netty.util.Timer; import org.apache.velocity.app.VelocityEngine; import org.traccar.broadcast.BroadcastService; import org.traccar.broadcast.MulticastBroadcastService; +import org.traccar.broadcast.RedisBroadcastService; import org.traccar.broadcast.NullBroadcastService; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -340,8 +341,16 @@ public class MainModule extends AbstractModule { @Provides public static BroadcastService provideBroadcastService( Config config, ObjectMapper objectMapper) throws IOException { + String broadcastType = config.getString(Keys.BROADCAST_TYPE); if (config.hasKey(Keys.BROADCAST_ADDRESS)) { - return new MulticastBroadcastService(config, objectMapper); + switch (broadcastType) { + case "multicast": + return new MulticastBroadcastService(config, objectMapper); + case "redis": + return new RedisBroadcastService(config, objectMapper); + default: + return new NullBroadcastService(); + } } return new NullBroadcastService(); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index d4780ba46..6f42e8937 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1755,6 +1755,14 @@ public final class Keys { List.of(KeyType.CONFIG), "time,position,speed,course,accuracy,result"); + /** + * Broadcast method. Available options are "multicast" and "redis". Default is "multicast". + */ + public static final ConfigKey BROADCAST_TYPE = new StringConfigKey( + "broadcast.type", + List.of(KeyType.CONFIG), + "multicast"); + /** * Multicast interface. It can be either an IP address or an interface name. */ -- cgit v1.2.3 From ffbfba88830561b27e1d15857fed664f4b7813ba Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 7 Jun 2023 06:49:14 -0700 Subject: Increase frame limit --- src/main/java/org/traccar/protocol/Minifinder2Protocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java index 61a43d8db..842194235 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java +++ b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java @@ -35,7 +35,7 @@ public class Minifinder2Protocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1200, 2, 2, 4, 0, true)); + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 2048, 2, 2, 4, 0, true)); pipeline.addLast(new Minifinder2ProtocolEncoder(Minifinder2Protocol.this)); pipeline.addLast(new Minifinder2ProtocolDecoder(Minifinder2Protocol.this)); } -- cgit v1.2.3 From 3397d4f07ef7fae909c0d6258dbc1263c4acc68b Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Thu, 8 Jun 2023 01:52:09 +0000 Subject: Add BaseBroadcastService pr comment adjustments --- src/main/java/org/traccar/MainModule.java | 2 +- .../traccar/broadcast/BaseBroadcastService.java | 118 ++++++++++++++ .../broadcast/MulticastBroadcastService.java | 92 +---------- .../traccar/broadcast/RedisBroadcastService.java | 176 ++++++--------------- src/main/java/org/traccar/config/Keys.java | 2 +- 5 files changed, 172 insertions(+), 218 deletions(-) create mode 100644 src/main/java/org/traccar/broadcast/BaseBroadcastService.java diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index b1a8006ee..29d846154 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -349,7 +349,7 @@ public class MainModule extends AbstractModule { case "redis": return new RedisBroadcastService(config, objectMapper); default: - return new NullBroadcastService(); + break; } } return new NullBroadcastService(); diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java new file mode 100644 index 000000000..1ed639dfd --- /dev/null +++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java @@ -0,0 +1,118 @@ +/* + * 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.broadcast; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.traccar.model.BaseModel; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Permission; +import org.traccar.model.Position; + +public abstract class BaseBroadcastService implements BroadcastService { + + private final Set listeners = new HashSet<>(); + + @Override + public boolean singleInstance() { + return true; + } + + @Override + public void registerListener(BroadcastInterface listener) { + listeners.add(listener); + } + + @Override + public void updateDevice(boolean local, Device device) { + BroadcastMessage message = new BroadcastMessage(); + message.setDevice(device); + sendMessage(message); + } + + @Override + public void updatePosition(boolean local, Position position) { + BroadcastMessage message = new BroadcastMessage(); + message.setPosition(position); + sendMessage(message); + } + + @Override + public void updateEvent(boolean local, long userId, Event event) { + BroadcastMessage message = new BroadcastMessage(); + message.setUserId(userId); + message.setEvent(event); + sendMessage(message); + } + + @Override + public void updateCommand(boolean local, long deviceId) { + BroadcastMessage message = new BroadcastMessage(); + message.setCommandDeviceId(deviceId); + sendMessage(message); + } + + @Override + public void invalidateObject(boolean local, Class clazz, long id) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz), id)); + sendMessage(message); + } + + @Override + public void invalidatePermission( + boolean local, + Class clazz1, long id1, + Class clazz2, long id2) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); + sendMessage(message); + } + + protected abstract void sendMessage(BroadcastMessage message); + + protected void handleMessage(BroadcastMessage message) { + if (message.getDevice() != null) { + listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); + } else if (message.getPosition() != null) { + listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); + } else if (message.getUserId() != null && message.getEvent() != null) { + listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); + } else if (message.getCommandDeviceId() != null) { + listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); + } else if (message.getChanges() != null) { + var iterator = message.getChanges().entrySet().iterator(); + if (iterator.hasNext()) { + var first = iterator.next(); + if (iterator.hasNext()) { + var second = iterator.next(); + listeners.forEach(listener -> listener.invalidatePermission( + false, + Permission.getKeyClass(first.getKey()), first.getValue(), + Permission.getKeyClass(second.getKey()), second.getValue())); + } else { + listeners.forEach(listener -> listener.invalidateObject( + false, + Permission.getKeyClass(first.getKey()), first.getValue())); + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java index b1b66f1e3..1c02b319b 100644 --- a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java @@ -20,11 +20,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.model.BaseModel; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Permission; -import org.traccar.model.Position; import java.io.IOException; import java.net.DatagramPacket; @@ -34,13 +29,10 @@ import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -public class MulticastBroadcastService implements BroadcastService { +public class MulticastBroadcastService extends BaseBroadcastService { private static final Logger LOGGER = LoggerFactory.getLogger(MulticastBroadcastService.class); @@ -55,8 +47,6 @@ public class MulticastBroadcastService implements BroadcastService { private final ExecutorService service = Executors.newSingleThreadExecutor(); private final byte[] receiverBuffer = new byte[4096]; - private final Set listeners = new HashSet<>(); - public MulticastBroadcastService(Config config, ObjectMapper objectMapper) throws IOException { this.objectMapper = objectMapper; port = config.getInteger(Keys.BROADCAST_PORT); @@ -76,57 +66,7 @@ public class MulticastBroadcastService implements BroadcastService { } @Override - public void registerListener(BroadcastInterface listener) { - listeners.add(listener); - } - - @Override - public void updateDevice(boolean local, Device device) { - BroadcastMessage message = new BroadcastMessage(); - message.setDevice(device); - sendMessage(message); - } - - @Override - public void updatePosition(boolean local, Position position) { - BroadcastMessage message = new BroadcastMessage(); - message.setPosition(position); - sendMessage(message); - } - - @Override - public void updateEvent(boolean local, long userId, Event event) { - BroadcastMessage message = new BroadcastMessage(); - message.setUserId(userId); - message.setEvent(event); - sendMessage(message); - } - - @Override - public void updateCommand(boolean local, long deviceId) { - BroadcastMessage message = new BroadcastMessage(); - message.setCommandDeviceId(deviceId); - sendMessage(message); - } - - @Override - public void invalidateObject(boolean local, Class clazz, long id) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz), id)); - sendMessage(message); - } - - @Override - public void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); - sendMessage(message); - } - - private void sendMessage(BroadcastMessage message) { + protected void sendMessage(BroadcastMessage message) { try { byte[] buffer = objectMapper.writeValueAsString(message).getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group); @@ -136,34 +76,6 @@ public class MulticastBroadcastService implements BroadcastService { } } - private void handleMessage(BroadcastMessage message) { - if (message.getDevice() != null) { - listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); - } else if (message.getPosition() != null) { - listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); - } else if (message.getUserId() != null && message.getEvent() != null) { - listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); - } else if (message.getCommandDeviceId() != null) { - listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); - } else if (message.getChanges() != null) { - var iterator = message.getChanges().entrySet().iterator(); - if (iterator.hasNext()) { - var first = iterator.next(); - if (iterator.hasNext()) { - var second = iterator.next(); - listeners.forEach(listener -> listener.invalidatePermission( - false, - Permission.getKeyClass(first.getKey()), first.getValue(), - Permission.getKeyClass(second.getKey()), second.getValue())); - } else { - listeners.forEach(listener -> listener.invalidateObject( - false, - Permission.getKeyClass(first.getKey()), first.getValue())); - } - } - } - } - @Override public void start() throws IOException { service.submit(receiver); diff --git a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java index a6968c894..e619fef60 100644 --- a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java @@ -20,23 +20,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.model.BaseModel; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Permission; -import org.traccar.model.Position; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.exceptions.JedisConnectionException; +import redis.clients.jedis.exceptions.JedisException; -public class RedisBroadcastService implements BroadcastService { +public class RedisBroadcastService extends BaseBroadcastService { private static final Logger LOGGER = LoggerFactory.getLogger(RedisBroadcastService.class); @@ -44,25 +38,25 @@ public class RedisBroadcastService implements BroadcastService { private final ExecutorService service = Executors.newSingleThreadExecutor(); - private final Set listeners = new HashSet<>(); - private final String url; - private final String pubsubChannel = "traccar:cast"; + private final String channel = "traccar"; - private final Jedis subscriberJedis; - private final Jedis publisherJedis; + private Jedis subscriber; + private Jedis publisher; - private final String id; + private final String id = UUID.randomUUID().toString(); public RedisBroadcastService(Config config, ObjectMapper objectMapper) throws IOException { this.objectMapper = objectMapper; url = config.getString(Keys.BROADCAST_ADDRESS); - subscriberJedis = new Jedis(url); - publisherJedis = new Jedis(url); - - // id that will be used to identify this instance of the server - id = String.valueOf(System.currentTimeMillis()); + try { + subscriber = new Jedis(url); + publisher = new Jedis(url); + subscriber.connect(); + } catch (JedisConnectionException e) { + throw new IOException(e); + } } @Override @@ -71,90 +65,14 @@ public class RedisBroadcastService implements BroadcastService { } @Override - public void registerListener(BroadcastInterface listener) { - listeners.add(listener); - } - - @Override - public void updateDevice(boolean local, Device device) { - BroadcastMessage message = new BroadcastMessage(); - message.setDevice(device); - sendMessage(message); - } - - @Override - public void updatePosition(boolean local, Position position) { - BroadcastMessage message = new BroadcastMessage(); - message.setPosition(position); - sendMessage(message); - } - - @Override - public void updateEvent(boolean local, long userId, Event event) { - BroadcastMessage message = new BroadcastMessage(); - message.setUserId(userId); - message.setEvent(event); - sendMessage(message); - } - - @Override - public void updateCommand(boolean local, long deviceId) { - BroadcastMessage message = new BroadcastMessage(); - message.setCommandDeviceId(deviceId); - sendMessage(message); - } - - @Override - public void invalidateObject(boolean local, Class clazz, long id) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz), id)); - sendMessage(message); - } - - @Override - public void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); - sendMessage(message); - } - - private void sendMessage(BroadcastMessage message) { + protected void sendMessage(BroadcastMessage message) { try { String payload = id + ":" + objectMapper.writeValueAsString(message); - publisherJedis.publish(pubsubChannel, payload); + publisher.publish(channel, payload); } catch (IOException e) { LOGGER.warn("Broadcast failed", e); - } - } - - private void handleMessage(BroadcastMessage message) { - if (message.getDevice() != null) { - listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); - } else if (message.getPosition() != null) { - listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); - } else if (message.getUserId() != null && message.getEvent() != null) { - listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); - } else if (message.getCommandDeviceId() != null) { - listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); - } else if (message.getChanges() != null) { - var iterator = message.getChanges().entrySet().iterator(); - if (iterator.hasNext()) { - var first = iterator.next(); - if (iterator.hasNext()) { - var second = iterator.next(); - listeners.forEach(listener -> listener.invalidatePermission( - false, - Permission.getKeyClass(first.getKey()), first.getValue(), - Permission.getKeyClass(second.getKey()), second.getValue())); - } else { - listeners.forEach(listener -> listener.invalidateObject( - false, - Permission.getKeyClass(first.getKey()), first.getValue())); - } - } + } catch (JedisConnectionException e) { + LOGGER.warn("Broadcast failed", e); } } @@ -165,39 +83,45 @@ public class RedisBroadcastService implements BroadcastService { @Override public void stop() { + try { + if (subscriber != null) { + subscriber.close(); + subscriber = null; + } + } catch (JedisException e) { + LOGGER.warn("Subscriber close failed", e); + } + try { + if (publisher != null) { + publisher.close(); + publisher = null; + } + } catch (JedisException e) { + LOGGER.warn("Publisher close failed", e); + } service.shutdown(); } private final Runnable receiver = new Runnable() { @Override public void run() { - subscriberJedis.subscribe(new JedisPubSub() { - @Override - public void onMessage(String channel, String message) { - try { - String[] parts = message.split(":", 2); - if (channel == pubsubChannel && parts.length == 2 && !id.equals(parts[0])) { - handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); + try { + subscriber.subscribe(new JedisPubSub() { + @Override + public void onMessage(String messageChannel, String message) { + try { + String[] parts = message.split(":", 2); + if (messageChannel == channel && parts.length == 2 && !id.equals(parts[0])) { + handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); + } + } catch (IOException e) { + LOGGER.warn("Broadcast handleMessage failed", e); } - } catch (IOException e) { - LOGGER.warn("Broadcast handleMessage failed", e); } - } - }, pubsubChannel); - - while (!service.isShutdown()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; - } - } - - try { - subscriberJedis.close(); - publisherJedis.close(); - } catch (Exception e) { - LOGGER.warn("Failed to close pubsub", e); + }, channel); + } catch (JedisConnectionException e) { + throw new RuntimeException(e); + } catch (JedisException e) { throw new RuntimeException(e); } } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6f42e8937..381e3a108 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1771,7 +1771,7 @@ public final class Keys { List.of(KeyType.CONFIG)); /** - * Multicast address for broadcasting synchronization events. + * Multicast address or Redis URL for broadcasting synchronization events. */ public static final ConfigKey BROADCAST_ADDRESS = new StringConfigKey( "broadcast.address", -- cgit v1.2.3 From a39af3b4d72f3ed8a6dfe868d365d6bbf34e18d3 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Fri, 9 Jun 2023 01:15:52 +0000 Subject: cleanup Breaking change: if using multicast must set broadcast.type="multicast" --- src/main/java/org/traccar/MainModule.java | 18 +++++++----------- .../org/traccar/broadcast/BaseBroadcastService.java | 2 +- src/main/java/org/traccar/config/Keys.java | 5 +++-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 29d846154..950a7278a 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -341,18 +341,14 @@ public class MainModule extends AbstractModule { @Provides public static BroadcastService provideBroadcastService( Config config, ObjectMapper objectMapper) throws IOException { - String broadcastType = config.getString(Keys.BROADCAST_TYPE); - if (config.hasKey(Keys.BROADCAST_ADDRESS)) { - switch (broadcastType) { - case "multicast": - return new MulticastBroadcastService(config, objectMapper); - case "redis": - return new RedisBroadcastService(config, objectMapper); - default: - break; - } + switch (config.getString(Keys.BROADCAST_TYPE)) { + case "multicast": + return new MulticastBroadcastService(config, objectMapper); + case "redis": + return new RedisBroadcastService(config, objectMapper); + default: + return new NullBroadcastService(); } - return new NullBroadcastService(); } @Singleton diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java index 1ed639dfd..a95d333f2 100644 --- a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java @@ -115,4 +115,4 @@ public abstract class BaseBroadcastService implements BroadcastService { } } -} \ No newline at end of file +} diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 381e3a108..78e081ce5 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1756,12 +1756,13 @@ public final class Keys { "time,position,speed,course,accuracy,result"); /** - * Broadcast method. Available options are "multicast" and "redis". Default is "multicast". + * Broadcast method. Available options are "multicast" and "redis". By default (if the value is not + * specified or does not matches available options) server disables broadcast. */ public static final ConfigKey BROADCAST_TYPE = new StringConfigKey( "broadcast.type", List.of(KeyType.CONFIG), - "multicast"); + ""); /** * Multicast interface. It can be either an IP address or an interface name. -- cgit v1.2.3 From dc22bc5feef7887d3baec1b2904fc18e1d067378 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Sat, 10 Jun 2023 14:01:11 +0000 Subject: cleanup broadcast type --- src/main/java/org/traccar/MainModule.java | 17 ++++++++++------- src/main/java/org/traccar/config/Keys.java | 3 +-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 950a7278a..b7bdbc6bf 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -341,14 +341,17 @@ public class MainModule extends AbstractModule { @Provides public static BroadcastService provideBroadcastService( Config config, ObjectMapper objectMapper) throws IOException { - switch (config.getString(Keys.BROADCAST_TYPE)) { - case "multicast": - return new MulticastBroadcastService(config, objectMapper); - case "redis": - return new RedisBroadcastService(config, objectMapper); - default: - return new NullBroadcastService(); + if (config.hasKey(Keys.BROADCAST_TYPE)) { + switch (config.getString(Keys.BROADCAST_TYPE)) { + case "multicast": + return new MulticastBroadcastService(config, objectMapper); + case "redis": + return new RedisBroadcastService(config, objectMapper); + default: + break; + } } + return new NullBroadcastService(); } @Singleton diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 78e081ce5..1ff1d1b51 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1761,8 +1761,7 @@ public final class Keys { */ public static final ConfigKey BROADCAST_TYPE = new StringConfigKey( "broadcast.type", - List.of(KeyType.CONFIG), - ""); + List.of(KeyType.CONFIG)); /** * Multicast interface. It can be either an IP address or an interface name. -- cgit v1.2.3 From 144aaea2f46d8936009f9320279f58a118b0653c Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Sat, 10 Jun 2023 19:05:46 +0000 Subject: fix: compare string by value --- src/main/java/org/traccar/broadcast/RedisBroadcastService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java index e619fef60..e87ad5e61 100644 --- a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java @@ -111,7 +111,7 @@ public class RedisBroadcastService extends BaseBroadcastService { public void onMessage(String messageChannel, String message) { try { String[] parts = message.split(":", 2); - if (messageChannel == channel && parts.length == 2 && !id.equals(parts[0])) { + if (messageChannel.equals(channel) && parts.length == 2 && !id.equals(parts[0])) { handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); } } catch (IOException e) { -- cgit v1.2.3 From 13544022b3bf855fdc63893aa3040ecc78fb4dbb Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Sun, 11 Jun 2023 11:05:46 +0200 Subject: Ruptela IO decoding for Odometer, OBD Odometer and OBD Speed --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 77df0deb7..8672d104a 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -108,6 +108,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 30: position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); break; + case 65: + position.set(Position.KEY_ODOMETER, readValue(buf, length, true)); + break; case 74: position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1); break; @@ -116,6 +119,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 80: position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1); break; + case 95: + position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(readValue(buf, length, true))); + break; case 134: if (readValue(buf, length, false) > 0) { position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); @@ -129,6 +135,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 197: position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125); break; + case 645: + position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, true) * 1000); + break; default: position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); break; -- cgit v1.2.3 From ea1e72277a264d69c2e4b9b15113dffcb6b7d662 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Sun, 11 Jun 2023 11:43:10 +0200 Subject: Ruptela IO Decoding for Device Temperature, Battery charging, Tow Alarm, Accident Alarm --- .../org/traccar/protocol/RuptelaProtocolDecoder.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 8672d104a..c9efd8f7b 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -108,6 +108,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 30: position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); break; + case 32: + position.set(Position.KEY_DEVICE_TEMP, readValue(buf, length, true)); + break; case 65: position.set(Position.KEY_ODOMETER, readValue(buf, length, true)); break; @@ -132,9 +135,22 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); } break; + case 170: + position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0); + break; case 197: position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125); break; + case 410: + if (readValue(buf, length, false) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + } + break; + case 411: + if (readValue(buf, length, false) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + } + break; case 645: position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, true) * 1000); break; -- cgit v1.2.3 From 873f08a8fd6e5e521e8c81421ebc2c3ea642ee52 Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Sun, 11 Jun 2023 13:30:48 +0300 Subject: Add increment value attribute on Duplicate Device Name for Route Report. Declaring uniqueSheetsTitle Add private method getUniqueSheetName Usage in getExcel sheetNames --- src/main/java/org/traccar/reports/RouteReportProvider.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index 6d44259e6..bec1470bd 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -42,6 +42,9 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; public class RouteReportProvider { @@ -66,7 +69,13 @@ public class RouteReportProvider { } return result; } + private final Map uniqueSheetsTitle = new HashMap<>(); + private String getUniqueSheetName(String key) { + AtomicInteger atomic = new AtomicInteger(uniqueSheetsTitle.getOrDefault(key, -1)); + uniqueSheetsTitle.put(key, atomic.incrementAndGet()); + return (uniqueSheetsTitle.get(key) > 0 ? key + "-" + uniqueSheetsTitle.get(key) : key); + } public void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException, IOException { @@ -78,7 +87,7 @@ public class RouteReportProvider { var positions = PositionUtil.getPositions(storage, device.getId(), from, to); DeviceReportSection deviceRoutes = new DeviceReportSection(); deviceRoutes.setDeviceName(device.getName()); - sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName())); + sheetNames.add(WorkbookUtil.createSafeSheetName(getUniqueSheetName(deviceRoutes.getDeviceName()))); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( new Columns.All(), new Condition.Equals("id", device.getGroupId()))); -- cgit v1.2.3 From c98f4706e648e835ef7ac460e4a12381562515cd Mon Sep 17 00:00:00 2001 From: Nikolay Vlahovski Date: Sun, 11 Jun 2023 18:02:33 +0300 Subject: Refactor getUniqueSheetName in RouteReportProvider Rename uniqueSheetsTitle to namesCount Increase default namesCount counter to 1 Move namesCount to top --- src/main/java/org/traccar/reports/RouteReportProvider.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index bec1470bd..a1d004dd1 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -44,13 +44,13 @@ import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.HashMap; -import java.util.concurrent.atomic.AtomicInteger; public class RouteReportProvider { private final Config config; private final ReportUtils reportUtils; private final Storage storage; + private final Map namesCount = new HashMap<>(); @Inject public RouteReportProvider(Config config, ReportUtils reportUtils, Storage storage) { @@ -69,12 +69,11 @@ public class RouteReportProvider { } return result; } - private final Map uniqueSheetsTitle = new HashMap<>(); + private String getUniqueSheetName(String key) { - AtomicInteger atomic = new AtomicInteger(uniqueSheetsTitle.getOrDefault(key, -1)); - uniqueSheetsTitle.put(key, atomic.incrementAndGet()); - return (uniqueSheetsTitle.get(key) > 0 ? key + "-" + uniqueSheetsTitle.get(key) : key); + namesCount.compute(key, (k, value) -> (value == null) ? 1 : (value + 1)); + return (namesCount.get(key) > 1 ? key + "-" + namesCount.get(key) : key); } public void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, -- cgit v1.2.3 From 7f2ded68ef015684f90bef59c055a1c980688069 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 11 Jun 2023 08:10:16 -0700 Subject: Clean up formatting --- src/main/java/org/traccar/reports/RouteReportProvider.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index a1d004dd1..5343652b7 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -50,6 +50,7 @@ public class RouteReportProvider { private final Config config; private final ReportUtils reportUtils; private final Storage storage; + private final Map namesCount = new HashMap<>(); @Inject @@ -72,9 +73,10 @@ public class RouteReportProvider { private String getUniqueSheetName(String key) { - namesCount.compute(key, (k, value) -> (value == null) ? 1 : (value + 1)); - return (namesCount.get(key) > 1 ? key + "-" + namesCount.get(key) : key); + namesCount.compute(key, (k, value) -> value == null ? 1 : (value + 1)); + return namesCount.get(key) > 1 ? key + '-' + namesCount.get(key) : key; } + public void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException, IOException { -- cgit v1.2.3 From f0aedd380e67488dfe73adf49f48a822ca4b232e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 11 Jun 2023 09:27:52 -0700 Subject: Additional VL502 parameters --- .../java/org/traccar/protocol/HuabaoProtocolDecoder.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index ee5ab19d6..3adfa7daf 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -880,9 +880,15 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x0539: position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01); break; + case 0x052B: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); + break; case 0x052D: position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); break; + case 0x052E: + position.set("airTemp", buf.readUnsignedByte() - 40); + break; case 0x0530: position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); break; @@ -892,6 +898,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x0536: position.set(Position.KEY_RPM, buf.readUnsignedShort()); break; + case 0x053D: + position.set("intakePressure", buf.readUnsignedShort() * 0.1); + break; + case 0x0544: + position.set("liquidLevel", buf.readUnsignedByte()); + break; case 0x0547: case 0x0548: position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); -- cgit v1.2.3 From 105e4b943e618d6fa8200d25225caeb4680c2080 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 16:49:33 +0200 Subject: Ruptela - saner ignition decoding --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 7 ++++--- traccar-web | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index c9efd8f7b..85f0d407a 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -99,9 +99,6 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 4: position.set("di" + (id - 1), readValue(buf, length, false)); break; - case 5: - position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); - break; case 29: position.set(Position.KEY_POWER, readValue(buf, length, false)); break; @@ -141,6 +138,10 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 197: position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125); break; + case 251: + case 409: + position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); + break; case 410: if (readValue(buf, length, false) > 0) { position.set(Position.KEY_ALARM, Position.ALARM_TOW); diff --git a/traccar-web b/traccar-web index f8048106d..877108d90 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit f8048106dacb36466ae221a8258da85f35db6e9d +Subproject commit 877108d9012301f2b149ae862af4cffe17dfb20d -- cgit v1.2.3 From 398128c7c3f7de283e9d35e74d96e4990381ef1b Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 17:10:01 +0200 Subject: Ruptela - motion, gps antenna alarm and inputs decoding improvements --- .../traccar/protocol/RuptelaProtocolDecoder.java | 21 +++++++++++++++++++++ traccar-web | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 85f0d407a..5fd7b755e 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -97,8 +97,21 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 2: case 3: case 4: + case 5: position.set("di" + (id - 1), readValue(buf, length, false)); break; + case 20: + position.set("ai3", readValue(buf, length, false)); + break; + case 21: + position.set("ai4", readValue(buf, length, false)); + break; + case 22: + position.set("ai1", readValue(buf, length, false)); + break; + case 23: + position.set("ai2", readValue(buf, length, false)); + break; case 29: position.set(Position.KEY_POWER, readValue(buf, length, false)); break; @@ -135,6 +148,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 170: position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0); break; + case 173: + position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); + break; case 197: position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125); break; @@ -152,6 +168,11 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); } break; + case 415: + if (readValue(buf, length, false) != 1) { + position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); + } + break; case 645: position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, true) * 1000); break; diff --git a/traccar-web b/traccar-web index 877108d90..cb7106f4b 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 877108d9012301f2b149ae862af4cffe17dfb20d +Subproject commit cb7106f4bfd6856470861890ea5e4c0bbc4703ac -- cgit v1.2.3 From 5ac55028cb315acec7e8f966c5ab11bdcc2c81bb Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 17:26:38 +0200 Subject: Ruptela - Tampering, Jamming and Network Operator decoding. --- .../java/org/traccar/protocol/RuptelaProtocolDecoder.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 5fd7b755e..2a552a874 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -132,6 +132,11 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 80: position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1); break; + case 88: + if (readValue(buf, length, false) == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); + } + break; case 95: position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(readValue(buf, length, true))); break; @@ -145,6 +150,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); } break; + case 150: + position.set(Position.KEY_OPERATOR, readValue(buf, length, false)); + break; case 170: position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0); break; @@ -176,6 +184,11 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 645: position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, true) * 1000); break; + case 758: + if (readValue(buf, length, false) == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + } + break; default: position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); break; -- cgit v1.2.3 From acbb3b36fab3f03682f454c3a64a1a5c5bef4fd5 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 18:15:28 +0200 Subject: Ruptela - use > 0 for boolean comparison --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 2a552a874..d86476f9a 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -157,14 +157,14 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0); break; case 173: - position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); + position.set(Position.KEY_MOTION, readValue(buf, length, false) > 0); break; case 197: position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125); break; case 251: case 409: - position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); + position.set(Position.KEY_IGNITION, readValue(buf, length, false) > 0); break; case 410: if (readValue(buf, length, false) > 0) { -- cgit v1.2.3 From 3e5447de31091bd9908a5d960a10ce52d1fd42f2 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 18:19:59 +0200 Subject: Revert traccar-web submodule update --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index cb7106f4b..f8048106d 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit cb7106f4bfd6856470861890ea5e4c0bbc4703ac +Subproject commit f8048106dacb36466ae221a8258da85f35db6e9d -- cgit v1.2.3 From d6bc465b25f4be9c15342395c12fa73198da0842 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 19:33:56 +0200 Subject: Ruptela - correctly decode the input prefixes --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index d86476f9a..c1fc95e34 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -98,19 +98,19 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 3: case 4: case 5: - position.set("di" + (id - 1), readValue(buf, length, false)); + position.set(Position.PREFIX_IN + (id - 1), readValue(buf, length, false)); break; case 20: - position.set("ai3", readValue(buf, length, false)); + position.set(Position.PREFIX_ADC + 3, readValue(buf, length, false)); break; case 21: - position.set("ai4", readValue(buf, length, false)); + position.set(Position.PREFIX_ADC + 4, readValue(buf, length, false)); break; case 22: - position.set("ai1", readValue(buf, length, false)); + position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false)); break; case 23: - position.set("ai2", readValue(buf, length, false)); + position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false)); break; case 29: position.set(Position.KEY_POWER, readValue(buf, length, false)); -- cgit v1.2.3 From 39ae0f3b25ba198c74a022bae059c45c4d0ac985 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 20:38:40 +0200 Subject: Ruptela - > 0 for boolean on the Jamming boolean --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index c1fc95e34..33372224b 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -133,7 +133,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1); break; case 88: - if (readValue(buf, length, false) == 1) { + if (readValue(buf, length, false) > 0) { position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); } break; -- cgit v1.2.3 From f40a3307d7b77fd007572ee80ba3f0a0dd05cb51 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 22:22:50 +0200 Subject: Ruptela - only use GPS Antenna Cut Alarm when we know for sure that it's disconnected. --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 33372224b..737d30f10 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -177,7 +177,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { } break; case 415: - if (readValue(buf, length, false) != 1) { + if (readValue(buf, length, false) == 0) { position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); } break; -- cgit v1.2.3 From 3ac7982d48bd7b3ed207a1461bc90a1cb7a888c4 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Mon, 12 Jun 2023 23:22:21 +0200 Subject: Ruptela - decode TCO Driver ID and BLE Beacon ID --- .../org/traccar/protocol/RuptelaProtocolDecoder.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 737d30f10..8a9bf21a4 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -285,6 +285,22 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { driverId.release(); } + Long tcoDriverIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 155); + Long tcoDriverIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 156); + if (tcoDriverIdPart1 != null && tcoDriverIdPart2 != null) { + ByteBuf driverId = Unpooled.copyLong(tcoDriverIdPart1, tcoDriverIdPart2); + position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII)); + driverId.release(); + } + + Long bleBeaconIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); + Long bleBeaconIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); + if (bleBeaconIdPart1 != null && bleBeaconIdPart2 != null) { + ByteBuf bleBeaconId = Unpooled.copyLong(bleBeaconIdPart1, bleBeaconIdPart2); + position.set("bleBeaconId", bleBeaconId.toString(StandardCharsets.US_ASCII)); + bleBeaconId.release(); + } + positions.add(position); } -- cgit v1.2.3 From f1de2533c3527aefc6f9eb15277128bb8d8ec3cb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 12 Jun 2023 21:57:27 -0700 Subject: Improve Watch frame decoder --- src/main/java/org/traccar/protocol/WatchFrameDecoder.java | 11 +++++++++-- src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java index f99bd52e2..ec67aa34d 100644 --- a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -27,7 +27,14 @@ public class WatchFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ']') + 1; + int endIndex = -1; + for (int i = buf.writerIndex() - 1; i >= buf.readerIndex(); i--) { + if (buf.getByte(i) == ']') { + endIndex = i + 1; + break; + } + } + if (endIndex > 0) { ByteBuf frame = Unpooled.buffer(); while (buf.readerIndex() < endIndex) { diff --git a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java index 8b0486322..bf212544c 100644 --- a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java @@ -10,6 +10,10 @@ public class WatchFrameDecoderTest extends ProtocolTest { var decoder = inject(new WatchFrameDecoder()); + verifyFrame( + binary("5b33472a3838303930303234322a303133442a55442c3132303632332c3134303032302c412c34382e3934393237332c4e2c20342e333738333036302c452c31382e35362c34332e382c302e302c31322c3130302c37362c3232363132302c302c30303030303030302c322c3235352c3230342c382c333131302c35353032352c3134362c333133302c34393239372c3132342c352c42616e67696e67576966692c33343a61313a65643a65313a39313a34662c2d37312c42415220576946692c33363a61323a65313a65643a61313a64652c2d37322c4e6574776f726b576966692c32363a64653a61313a65643a65313a61302c2d37332c46696265722c33363a61313a65643a65313a39313a34662c2d37352c5b4c475f57616c6c2d4d6f756e7420412f435d653732352c36363a61313a65643a65313a65373a32352c2d38322c31352e305d"), + decoder.decode(null, null, binary("5b33472a3838303930303234322a303133442a55442c3132303632332c3134303032302c412c34382e3934393237332c4e2c20342e333738333036302c452c31382e35362c34332e382c302e302c31322c3130302c37362c3232363132302c302c30303030303030302c322c3235352c3230342c382c333131302c35353032352c3134362c333133302c34393239372c3132342c352c42616e67696e67576966692c33343a61313a65643a65313a39313a34662c2d37312c42415220576946692c33363a61323a65313a65643a61313a64652c2d37322c4e6574776f726b576966692c32363a64653a61313a65643a65313a61302c2d37332c46696265722c33363a61313a65643a65313a39313a34662c2d37352c5b4c475f57616c6c2d4d6f756e7420412f435d653732352c36363a61313a65643a65313a65373a32352c2d38322c31352e305d"))); + verifyFrame( binary("5b33472a3335323636313039303134333135302a303030412a4c4b2c302c302c3130305d"), decoder.decode(null, null, binary("5b33472a3335323636313039303134333135302a303030412a4c4b2c302c302c3130305d"))); -- cgit v1.2.3 From a3a086cfda4219815cba4ea6ca2cb44028c1e091 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Tue, 13 Jun 2023 13:37:24 +0200 Subject: Ruptela - tested bleBeaconID decoding --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 8a9bf21a4..2680e56b2 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -293,12 +293,10 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { driverId.release(); } - Long bleBeaconIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); - Long bleBeaconIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); - if (bleBeaconIdPart1 != null && bleBeaconIdPart2 != null) { - ByteBuf bleBeaconId = Unpooled.copyLong(bleBeaconIdPart1, bleBeaconIdPart2); - position.set("bleBeaconId", bleBeaconId.toString(StandardCharsets.US_ASCII)); - bleBeaconId.release(); + Long bleBeaconIdP1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); + Long bleBeaconIdP2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); + if (bleBeaconIdP1 != null && bleBeaconIdP2 != null) { + position.set("bleBeaconId", Long.toHexString(bleBeaconIdP1) + Long.toHexString(bleBeaconIdP2)); } positions.add(position); -- cgit v1.2.3 From cbfc5e524c98115ae0b1a4fb0754e9841a4fb915 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Tue, 13 Jun 2023 15:49:46 +0200 Subject: Ruptela renamed bleBeaconId to tagId --- .../org/traccar/protocol/RuptelaProtocolDecoder.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 2680e56b2..1f2887859 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -285,18 +285,18 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { driverId.release(); } - Long tcoDriverIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 155); - Long tcoDriverIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 156); - if (tcoDriverIdPart1 != null && tcoDriverIdPart2 != null) { - ByteBuf driverId = Unpooled.copyLong(tcoDriverIdPart1, tcoDriverIdPart2); + driverIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 155); + driverIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 156); + if (driverIdPart1 != null && driverIdPart2 != null) { + ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2); position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII)); driverId.release(); } - Long bleBeaconIdP1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); - Long bleBeaconIdP2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); - if (bleBeaconIdP1 != null && bleBeaconIdP2 != null) { - position.set("bleBeaconId", Long.toHexString(bleBeaconIdP1) + Long.toHexString(bleBeaconIdP2)); + Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); + Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); + if (tagIdPart1 != null && tagIdPart2 != null) { + position.set("tagId", Long.toHexString(tagIdPart1) + Long.toHexString(tagIdPart2)); } positions.add(position); -- cgit v1.2.3 From 262f8df7724966862482a5b1837462dad77ce074 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Tue, 13 Jun 2023 15:57:27 +0200 Subject: Ruptela restructure driver decoding --- .../traccar/protocol/RuptelaProtocolDecoder.java | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 1f2887859..2f127c70c 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -92,6 +92,16 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { } } + private void decodeDriver(Position position, String part1, String part2) { + Long driverIdPart1 = (Long) position.getAttributes().remove(part1); + Long driverIdPart2 = (Long) position.getAttributes().remove(part2); + if (driverIdPart1 != null && driverIdPart2 != null) { + ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2); + position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII)); + driverId.release(); + } + } + private void decodeParameter(Position position, int id, ByteBuf buf, int length) { switch (id) { case 2: @@ -277,21 +287,11 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { decodeParameter(position, id, buf, 8); } - Long driverIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 126); - Long driverIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 127); - if (driverIdPart1 != null && driverIdPart2 != null) { - ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2); - position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII)); - driverId.release(); - } + // CAN first driver ID + decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); - driverIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 155); - driverIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 156); - if (driverIdPart1 != null && driverIdPart2 != null) { - ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2); - position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII)); - driverId.release(); - } + // TCO first driver ID + decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); -- cgit v1.2.3 From ea3ea7f53970817bf5dc2cf6b28f48f0836b3245 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Tue, 13 Jun 2023 16:51:30 +0200 Subject: Update src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java Co-authored-by: Anton Tananaev --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 2f127c70c..1755ba8a8 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -287,11 +287,8 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { decodeParameter(position, id, buf, 8); } - // CAN first driver ID - decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); - - // TCO first driver ID - decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); + decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); // can driver + decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); // tco driver Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); -- cgit v1.2.3 From 94fbc93f8b0a75fe17e529355c4e7758b81b4776 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 14 Jun 2023 22:21:18 -0700 Subject: Additional Atrack parameters --- .../org/traccar/protocol/AtrackProtocolDecoder.java | 17 +++++++++++++++++ .../org/traccar/protocol/AtrackProtocolDecoderTest.java | 3 +++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java index aa19e9e41..8896dcfb0 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java @@ -614,6 +614,23 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { case "JN5": buf.readUnsignedInt(); // pto fuel break; + case "IN0": + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + break; + case "IN1": + case "IN2": + case "IN3": + position.set(Position.PREFIX_IN + key.charAt(2), buf.readUnsignedByte() > 0); + break; + case "HA": + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_ACCELERATION : null); + break; + case "HB": + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_BRAKING : null); + break; + case "HC": + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_CORNERING : null); + break; default: break; } diff --git a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java index 32000c4a7..be6fb5c45 100644 --- a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -43,6 +43,9 @@ public class AtrackProtocolDecoderTest extends ProtocolTest { decoder.setCustom(true); + verifyPositions(decoder, binary( + "4050d78502e01d29000312fa45441d6d647d8e67647d8e67647eef190205437c021846e6001a020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010c0000000000000000000000000000000000000000000000000e647d8e85647d8e86647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010c0000000000000000000000000000000000000000000000000e647d8ea3647d8ea4647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010b0000000000000000000000000000000000000000000000000e647d8ec1647d8ec2647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e647d8edf647d8ee0647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e647d8efd647d8efe647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e")); + verifyPositions(decoder, binary( "405099280272000300014399e3f93d136438abdf644083f56440842afb2711c701b9eaee0067020003e0bb03de0000000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000930025000000000000000000000000000000006438abdf644083f76440842afb2711c701b9eaee0067710003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000950025000000000000000000000000000000006438abdf644083f76440842afb2711c701b9eaee0067840003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000950025000000000000000000000000000000006438abdf644083f86440842afb2711c701b9eaee0067760003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c340000000000000000000000000000000000000000000095002500000000000000000000000000000000")); -- cgit v1.2.3 From 03650fff8064b60ffcda75f9033fd44e66ef34b3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 15 Jun 2023 05:35:09 -0700 Subject: Galileo Iridium frame decoding --- .../java/org/traccar/protocol/GalileoFrameDecoder.java | 16 +++++++++++----- .../org/traccar/protocol/GalileoFrameDecoderTest.java | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java index c23d26c83..d90e48287 100644 --- a/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -22,7 +22,7 @@ import org.traccar.BaseFrameDecoder; public class GalileoFrameDecoder extends BaseFrameDecoder { - private static final int MESSAGE_MINIMUM_LENGTH = 5; + private static final int MESSAGE_MINIMUM_LENGTH = 6; @Override protected Object decode( @@ -32,9 +32,15 @@ public class GalileoFrameDecoder extends BaseFrameDecoder { return null; } - int length = buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff; - if (buf.readableBytes() >= (length + MESSAGE_MINIMUM_LENGTH)) { - return buf.readRetainedSlice(length + MESSAGE_MINIMUM_LENGTH); + int length; + if (buf.getByte(buf.readerIndex()) == 0x01 && buf.getUnsignedMedium(buf.readerIndex() + 3) == 0x01001c) { + length = 3 + buf.getUnsignedShort(buf.readerIndex() + 1); + } else { + length = 5 + (buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff); + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); } return null; diff --git a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java index 256517460..530f0930e 100644 --- a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java @@ -12,6 +12,10 @@ public class GalileoFrameDecoderTest extends ProtocolTest { var decoder = inject(new GalileoFrameDecoder()); + assertEquals( + binary("01003f01001c475b166133303035333430363431383437393000001d000064897bb003000b0221c20512a60a0000000802000f209d7b8964300f2536fbfd103c1d01"), + decoder.decode(null, null, binary("01003f01001c475b166133303035333430363431383437393000001d000064897bb003000b0221c20512a60a0000000802000f209d7b8964300f2536fbfd103c1d01"))); + assertEquals( binary("011780011102e603383633353931303238393630323437043200801c"), decoder.decode(null, null, binary("011780011102e603383633353931303238393630323437043200801c"))); -- cgit v1.2.3 From 4a64ef748e207406be4f7aa7538d59b7b0f9735c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 15 Jun 2023 05:53:04 -0700 Subject: Decode JT808 battery level --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 6 ++++++ src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 3adfa7daf..beb1ec41a 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -484,6 +484,10 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01); } break; + case 0x56: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 10); + buf.readUnsignedByte(); // reserved + break; case 0x60: position.set(Position.KEY_EVENT, buf.readUnsignedShort()); buf.skipBytes(length - 2); @@ -692,6 +696,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0xFE: if (length == 1) { position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + } else if (length == 2) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); } else { int mark = buf.readUnsignedByte(); if (mark == 0x7C) { diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 5fd9ed894..9c3fc164a 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); + verifyAttribute(decoder, binary( + "7e0200003f014501643822000300020000000c000c0000000000000000000000000000230615143903300111310100530901027f0300456f073e56020900fe02001e57080002000200000000df7e"), + Position.KEY_BATTERY_LEVEL, 90); + verifyAttribute(decoder, binary( "7e090000344f07788ef87d0138f02305151230460102020001ffffffff000100001457000000020006503134353700000c000a029dc63004b99a98230515132726787e"), Position.KEY_DTCS, "P1457"); -- cgit v1.2.3 From e7ca96d67650f0d8059983ff63c6ea31b562b481 Mon Sep 17 00:00:00 2001 From: memesaregood Date: Thu, 15 Jun 2023 17:01:34 +0300 Subject: Allowed primitive Java types in JEXL Engine --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index d384bbffc..24d853bbe 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -65,6 +65,14 @@ public class ComputedAttributesHandler extends BaseDataHandler { JexlSandbox sandbox = new JexlSandbox(false); sandbox.allow("com.safe.Functions"); sandbox.allow(Math.class.getName()); + sandbox.allow(Double.class.getName()); + sandbox.allow(Float.class.getName()); + sandbox.allow(Integer.class.getName()); + sandbox.allow(Long.class.getName()); + sandbox.allow(Short.class.getName()); + sandbox.allow(Character.class.getName()); + sandbox.allow(Boolean.class.getName()); + sandbox.allow(String.class.getName()); features = new JexlFeatures() .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS)) -- cgit v1.2.3 From 57414098b8295e91d9c2436cf4be18c0ef430fd3 Mon Sep 17 00:00:00 2001 From: memesaregood Date: Thu, 15 Jun 2023 17:55:28 +0300 Subject: Use a lambda expression to allow the primitive types --- .../java/org/traccar/handler/ComputedAttributesHandler.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 24d853bbe..29d9bcdcb 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.List; import io.netty.channel.ChannelHandler; import org.apache.commons.jexl3.JexlFeatures; @@ -65,14 +66,10 @@ public class ComputedAttributesHandler extends BaseDataHandler { JexlSandbox sandbox = new JexlSandbox(false); sandbox.allow("com.safe.Functions"); sandbox.allow(Math.class.getName()); - sandbox.allow(Double.class.getName()); - sandbox.allow(Float.class.getName()); - sandbox.allow(Integer.class.getName()); - sandbox.allow(Long.class.getName()); - sandbox.allow(Short.class.getName()); - sandbox.allow(Character.class.getName()); - sandbox.allow(Boolean.class.getName()); - sandbox.allow(String.class.getName()); + List.of(Double.class, Float.class, Integer.class, + Long.class, Short.class, Character.class, + Boolean.class, String.class, Byte.class) + .forEach((type) -> sandbox.allow(type.getName())); features = new JexlFeatures() .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS)) -- cgit v1.2.3 From 2275e7d4e739eab9e24eab66d068cf0afafc5bb8 Mon Sep 17 00:00:00 2001 From: memesaregood1 <63505425+memesaregood1@users.noreply.github.com> Date: Thu, 15 Jun 2023 21:09:50 +0300 Subject: Update src/main/java/org/traccar/handler/ComputedAttributesHandler.java Co-authored-by: Anton Tananaev --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 29d9bcdcb..8ad4e41e4 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -66,9 +66,9 @@ public class ComputedAttributesHandler extends BaseDataHandler { JexlSandbox sandbox = new JexlSandbox(false); sandbox.allow("com.safe.Functions"); sandbox.allow(Math.class.getName()); - List.of(Double.class, Float.class, Integer.class, - Long.class, Short.class, Character.class, - Boolean.class, String.class, Byte.class) + List.of( + Double.class, Float.class, Integer.class, Long.class, Short.class, + Character.class, Boolean.class, String.class, Byte.class) .forEach((type) -> sandbox.allow(type.getName())); features = new JexlFeatures() .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) -- cgit v1.2.3 From 8ee2199cff0596790111e5ead43ec3da29a440dc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Jun 2023 07:00:57 -0700 Subject: Do not count service account --- src/main/java/org/traccar/database/StatisticsManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index e0995dabc..c8a36bf78 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.api.security.ServiceAccountUser; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.DateUtil; @@ -147,7 +148,7 @@ public class StatisticsManager { public synchronized void registerRequest(long userId) { checkSplit(); requests += 1; - if (userId != 0) { + if (userId != 0 && userId != ServiceAccountUser.ID) { users.add(userId); } } -- cgit v1.2.3 From 2d45e488f090d54d87319adc65147a3998f0d3c3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Jun 2023 07:02:46 -0700 Subject: Add GV500MAP test case --- src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 4b0edfd81..a73127546 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyNull(decoder, buffer( + "+RESP:GTFRI,5E0100,862061048023666,,,12940,10,1,1,0.0,97,179.8,-90.366478,38.735379,20230616183231,0310,0410,6709,03ADF710,00,6223.7,,,,,110000,,,,202306161834$")); + verifyAttribute(decoder, buffer( "+BUFF:GTERI,410502,864802030794634,,00000001,,10,1,1,0.0,0,3027.8,-78.706612,-0.955699,20230418170736,0740,0002,A08C,2AB72D,00,0.0,,,,100,110000,1,0099,20230418171004,8B98$"), Position.KEY_FUEL_LEVEL, 153); -- cgit v1.2.3 From ef99a5067522d5affcd0550eb299e37c916e3096 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 18 Jun 2023 07:41:43 -0700 Subject: Add daily limit filter --- src/main/java/org/traccar/config/Keys.java | 7 +++++++ src/main/java/org/traccar/database/StatisticsManager.java | 7 +++++++ src/main/java/org/traccar/handler/FilterHandler.java | 15 ++++++++++++++- src/test/java/org/traccar/handler/FilterHandlerTest.java | 4 ++-- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 1ff1d1b51..04bf10fe7 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1327,6 +1327,13 @@ public final class Keys { "filter.minPeriod", List.of(KeyType.CONFIG)); + /** + * Filter position if the daily limit is exceeded for the device. + */ + public static final ConfigKey FILTER_DAILY_LIMIT = new IntegerConfigKey( + "filter.dailyLimit", + List.of(KeyType.CONFIG)); + /** * If false, the server expects all locations to come sequentially (for each device). Filter checks for duplicates, * distance, speed, or time period only against the location that was last received by server. diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index c8a36bf78..e417c8901 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -58,6 +58,7 @@ public class StatisticsManager { private final Set users = new HashSet<>(); private final Map deviceProtocols = new HashMap<>(); + private final Map deviceMessages = new HashMap<>(); private int requests; private int messagesReceived; @@ -101,6 +102,7 @@ public class StatisticsManager { users.clear(); deviceProtocols.clear(); + deviceMessages.clear(); requests = 0; messagesReceived = 0; messagesStored = 0; @@ -163,9 +165,14 @@ public class StatisticsManager { messagesStored += 1; if (deviceId != 0) { deviceProtocols.put(deviceId, protocol); + deviceMessages.merge(deviceId, 1, Integer::sum); } } + public synchronized int messageStoredCount(long deviceId) { + return deviceMessages.getOrDefault(deviceId, 0); + } + public synchronized void registerMail() { checkSplit(); mailSent += 1; diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 9ff94deb0..37c3beddf 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -22,6 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; +import org.traccar.database.StatisticsManager; import org.traccar.helper.UnitsConverter; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Device; @@ -57,15 +58,18 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { private final int filterDistance; private final int filterMaxSpeed; private final long filterMinPeriod; + private final int filterDailyLimit; private final boolean filterRelative; private final long skipLimit; private final boolean skipAttributes; private final CacheManager cacheManager; private final Storage storage; + private final StatisticsManager statisticsManager; @Inject - public FilterHandler(Config config, CacheManager cacheManager, Storage storage) { + public FilterHandler( + Config config, CacheManager cacheManager, Storage storage, StatisticsManager statisticsManager) { enabled = config.getBoolean(Keys.FILTER_ENABLE); filterInvalid = config.getBoolean(Keys.FILTER_INVALID); filterZero = config.getBoolean(Keys.FILTER_ZERO); @@ -79,11 +83,13 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { filterDistance = config.getInteger(Keys.FILTER_DISTANCE); filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED); filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000L; + filterDailyLimit = config.getInteger(Keys.FILTER_DAILY_LIMIT); filterRelative = config.getBoolean(Keys.FILTER_RELATIVE); skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000; skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE); this.cacheManager = cacheManager; this.storage = storage; + this.statisticsManager = statisticsManager; } private Position getPrecedingPosition(long deviceId, Date date) throws StorageException { @@ -165,6 +171,13 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { return false; } + private boolean filterDailyLimit(Position position) { + if (filterDailyLimit != 0) { + return statisticsManager.messageStoredCount(position.getDeviceId()) >= filterDailyLimit; + } + return false; + } + private boolean skipLimit(Position position, Position last) { if (skipLimit != 0 && last != null) { return (position.getServerTime().getTime() - last.getServerTime().getTime()) > skipLimit; diff --git a/src/test/java/org/traccar/handler/FilterHandlerTest.java b/src/test/java/org/traccar/handler/FilterHandlerTest.java index 26281e351..14037f723 100644 --- a/src/test/java/org/traccar/handler/FilterHandlerTest.java +++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java @@ -29,7 +29,7 @@ public class FilterHandlerTest extends BaseTest { when(config.getBoolean(Keys.FILTER_ENABLE)).thenReturn(true); var cacheManager = mock(CacheManager.class); when(cacheManager.getConfig()).thenReturn(config); - passingHandler = new FilterHandler(config, cacheManager, null); + passingHandler = new FilterHandler(config, cacheManager, null, null); } @BeforeEach @@ -50,7 +50,7 @@ public class FilterHandlerTest extends BaseTest { var cacheManager = mock(CacheManager.class); when(cacheManager.getConfig()).thenReturn(config); when(cacheManager.getObject(any(), anyLong())).thenReturn(mock(Device.class)); - filteringHandler = new FilterHandler(config, cacheManager, null); + filteringHandler = new FilterHandler(config, cacheManager, null, null); } private Position createPosition(Date time, boolean valid, double speed) { -- cgit v1.2.3 From ba8191373d55d6115427ef7187b8f2d0650a5ec5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 18 Jun 2023 07:47:58 -0700 Subject: Apply the filter --- src/main/java/org/traccar/handler/FilterHandler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 37c3beddf..2623c3486 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -223,6 +223,9 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { if (filterApproximate(position)) { filterType.append("Approximate "); } + if (filterDailyLimit(position)) { + filterType.append("DailyLimit "); + } // filter out excessive data long deviceId = position.getDeviceId(); -- cgit v1.2.3 From a2c35b1c98a56d07924f955bb6d4172f27623816 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 20 Jun 2023 08:35:49 -0700 Subject: Decode Eview status bits --- .../java/org/traccar/protocol/Minifinder2ProtocolDecoder.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index f660f2e92..f8b0c34e9 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -239,6 +239,14 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { case 0x24: position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); long status = buf.readUnsignedIntLE(); + if (BitUtil.check(status, 4)) { + position.set(Position.KEY_CHARGE, true); + } + if (BitUtil.check(status, 7)) { + position.set(Position.KEY_ARCHIVE, true); + } + position.set(Position.KEY_MOTION, BitUtil.check(status, 9)); + position.set(Position.KEY_RSSI, BitUtil.between(status, 19, 24)); position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(status, 24)); position.set(Position.KEY_STATUS, status); break; -- cgit v1.2.3 From a3b03c7744a6767cede6725ba7089823e11b983a Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 21 Jun 2023 00:18:46 +0200 Subject: Ruptela Decoder - implement Extended protocol extended messages merging --- .../java/org/traccar/protocol/RuptelaProtocolDecoder.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 1755ba8a8..294768860 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -236,7 +236,18 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // timestamp extension if (type == MSG_EXTENDED_RECORDS) { - buf.readUnsignedByte(); // record extension + int b = buf.readUnsignedByte(); // record extension + int noRecordsToMerge = (b & 0xf0) >> 4; + int currentRecord = b & 0x0f; + + if (currentRecord > 0 && noRecordsToMerge >= currentRecord) { + if (!positions.isEmpty() + && positions.get(positions.size() - 1).getDeviceTime() + .compareTo(position.getDeviceTime()) == 0) { + position = positions.remove(positions.size() - 1); + } + } + } buf.readUnsignedByte(); // priority (reserved) -- cgit v1.2.3 From b8e9d39d711c0d9f2af26aa90bfb167af364a8d3 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 21 Jun 2023 12:00:52 +0200 Subject: Ruptela Decoder use Bitutil for record extension merging --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 294768860..ecb5c4204 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -22,6 +22,7 @@ import org.traccar.BaseProtocolDecoder; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; +import org.traccar.helper.BitUtil; import org.traccar.helper.DataConverter; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; @@ -236,9 +237,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // timestamp extension if (type == MSG_EXTENDED_RECORDS) { - int b = buf.readUnsignedByte(); // record extension - int noRecordsToMerge = (b & 0xf0) >> 4; - int currentRecord = b & 0x0f; + int recordExtension = buf.readUnsignedByte(); // record extension + int noRecordsToMerge = BitUtil.between(recordExtension, 4, 8); + int currentRecord = BitUtil.to(recordExtension, 4); if (currentRecord > 0 && noRecordsToMerge >= currentRecord) { if (!positions.isEmpty() @@ -247,7 +248,6 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position = positions.remove(positions.size() - 1); } } - } buf.readUnsignedByte(); // priority (reserved) -- cgit v1.2.3 From 149db397ce7bbf60834260a7585366e515c8de24 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 21 Jun 2023 12:08:23 +0200 Subject: Ruptela Decoder - power factor standardization --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index ecb5c4204..1d627c5f3 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -124,7 +124,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false)); break; case 29: - position.set(Position.KEY_POWER, readValue(buf, length, false)); + position.set(Position.KEY_POWER, readValue(buf, length, false) * 0.001); break; case 30: position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); -- cgit v1.2.3 From 5ee370870401ae2e18a477d01f22128c6109f015 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 21 Jun 2023 19:11:40 +0200 Subject: Update src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java Co-authored-by: Anton Tananaev --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 1d627c5f3..79e8e1091 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -241,7 +241,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { int noRecordsToMerge = BitUtil.between(recordExtension, 4, 8); int currentRecord = BitUtil.to(recordExtension, 4); - if (currentRecord > 0 && noRecordsToMerge >= currentRecord) { + if (currentRecord > 0 && currentRecord <= noRecordsToMerge) { if (!positions.isEmpty() && positions.get(positions.size() - 1).getDeviceTime() .compareTo(position.getDeviceTime()) == 0) { -- cgit v1.2.3 From 648e7f652a5ca1024813864b2dea2572c9f5e3f0 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 21 Jun 2023 19:12:09 +0200 Subject: Update src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java Co-authored-by: Anton Tananaev --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 79e8e1091..a8296771a 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -237,7 +237,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // timestamp extension if (type == MSG_EXTENDED_RECORDS) { - int recordExtension = buf.readUnsignedByte(); // record extension + int recordExtension = buf.readUnsignedByte(); int noRecordsToMerge = BitUtil.between(recordExtension, 4, 8); int currentRecord = BitUtil.to(recordExtension, 4); -- cgit v1.2.3 From e43d353b7cc0f2bf34a77d58529c1360683d81c1 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 21 Jun 2023 19:15:44 +0200 Subject: Ruptela Decoder - extended records merging, remove redudant checks and better variable naming --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index a8296771a..d067d2ddc 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -238,15 +238,11 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { if (type == MSG_EXTENDED_RECORDS) { int recordExtension = buf.readUnsignedByte(); - int noRecordsToMerge = BitUtil.between(recordExtension, 4, 8); + int mergeRecordCount = BitUtil.between(recordExtension, 4, 8); int currentRecord = BitUtil.to(recordExtension, 4); - if (currentRecord > 0 && currentRecord <= noRecordsToMerge) { - if (!positions.isEmpty() - && positions.get(positions.size() - 1).getDeviceTime() - .compareTo(position.getDeviceTime()) == 0) { - position = positions.remove(positions.size() - 1); - } + if (currentRecord > 0 && currentRecord <= mergeRecordCount) { + position = positions.remove(positions.size() - 1); } } -- cgit v1.2.3 From eccbcfdd6906979763d0825f2b112a3050343381 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 21 Jun 2023 19:48:25 +0200 Subject: Update src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java Co-authored-by: Anton Tananaev --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index d067d2ddc..2122d5081 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -238,7 +238,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { if (type == MSG_EXTENDED_RECORDS) { int recordExtension = buf.readUnsignedByte(); - int mergeRecordCount = BitUtil.between(recordExtension, 4, 8); + int mergeRecordCount = BitUtil.from(recordExtension, 4); int currentRecord = BitUtil.to(recordExtension, 4); if (currentRecord > 0 && currentRecord <= mergeRecordCount) { -- cgit v1.2.3 From d2909b90af2344176d2018bdbb2f410ea6e44465 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 22 Jun 2023 06:41:05 -0700 Subject: Decode Fifotrack engine hours --- src/main/java/org/traccar/model/Position.java | 2 +- src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 3ed340703..6685cab95 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -42,7 +42,7 @@ public class Position extends Message { public static final String KEY_ODOMETER = "odometer"; // meters public static final String KEY_ODOMETER_SERVICE = "serviceOdometer"; // meters public static final String KEY_ODOMETER_TRIP = "tripOdometer"; // meters - public static final String KEY_HOURS = "hours"; + public static final String KEY_HOURS = "hours"; // milliseconds public static final String KEY_STEPS = "steps"; public static final String KEY_HEART_RATE = "heartRate"; public static final String KEY_INPUT = "input"; diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index e0dd1d62d..14b33b67f 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -64,7 +64,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // course .number("(-?d+),") // altitude .number("(d+),") // odometer - .number("d+,") // runtime + .number("(d+),") // engine hours .number("(x+),") // status .number("(x+)?,") // input .number("(x+)?,") // output @@ -290,6 +290,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { position.setAltitude(parser.nextInt()); position.set(Position.KEY_ODOMETER, parser.nextLong()); + position.set(Position.KEY_HOURS, parser.nextLong() * 1000); long status = parser.nextHexLong(); position.set(Position.KEY_RSSI, BitUtil.between(status, 3, 8)); -- cgit v1.2.3 From f8adf8eff8cc094e6a1a583a4fb3a11c6e8752e2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 24 Jun 2023 21:06:51 -0700 Subject: Add MariaDB native driver --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 727d2342e..b4e11ed98 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,7 @@ dependencies { implementation "commons-codec:commons-codec:1.15" implementation "com.h2database:h2:2.1.214" implementation "com.mysql:mysql-connector-j:8.0.33" + implementation "org.mariadb.jdbc:mariadb-java-client:3.1.4" implementation "org.postgresql:postgresql:42.6.0" implementation "com.microsoft.sqlserver:mssql-jdbc:12.2.0.jre11" implementation "com.zaxxer:HikariCP:5.0.1" -- cgit v1.2.3 From 2088a59da55e581391f9a768003b68baca467007 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Jun 2023 07:21:23 -0700 Subject: Xexun2 signed signal strength --- src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java index 913dfaf28..46e3dd118 100644 --- a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java @@ -164,7 +164,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { for (int j = 0; j < cellCount; j++) { network.addCellTower(CellTower.from( buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readInt(), buf.readUnsignedInt(), buf.readUnsignedByte())); + buf.readInt(), buf.readUnsignedInt(), buf.readByte())); } } if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) { -- cgit v1.2.3 From 3b6900a95342ae87861cfcae8870ac790da7a504 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Jun 2023 22:33:54 -0700 Subject: Support services message type --- src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java | 2 +- .../java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index f8b0c34e9..cd8d8e0cf 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -151,7 +151,7 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { sendResponse(channel, remoteAddress, index, type, buf); } - if (type == MSG_DATA) { + if (type == MSG_DATA || type == MSG_SERVICES) { List positions = new LinkedList<>(); Set keys = new HashSet<>(); diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java index 693a11fc5..587a520d1 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java @@ -24,10 +24,10 @@ public class Minifinder2ProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, binary( "ab10350015ae59010110013836333932313033333836353231360924723a12610042535a182ac0f6b4f2923100c900af02215c2b9bfb5461736b4c4d53")); - verifyNull(decoder, binary( + verifyPositions(decoder, false, binary( "ab10150076f1320003100133353534363530373130323933303602105a")); - verifyNull(decoder, binary( + verifyPositions(decoder, false, binary( "AB101400594A01000310013836333932323033343437333734350112")); verifyPositions(decoder, binary( -- cgit v1.2.3 From 1b899329364619cbdc4213e2fd065955a94f5c6c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Jun 2023 22:39:23 -0700 Subject: Fix Fifotrack Q2 decoding --- src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index 14b33b67f..c30398d36 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -235,8 +235,8 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { position.setValid(parser.next().equals("A")); position.setFixTime(position.getDeviceTime()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.set(Position.KEY_SATELLITES, parser.nextInt()); position.setLatitude(parser.nextDouble()); position.setLongitude(parser.nextDouble()); diff --git a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java index 518eada52..cbfc46703 100644 --- a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class FifotrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new FifotrackProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "$$99,865413050150407,7F,A03,,230626072722,460|0|25FC|AC2AB0B,3.74,52,0019,0,A,0,13,22.643466,114.018211*74"), + Position.KEY_SATELLITES, 13); + verifyPosition(decoder, buffer( "$$95,866104023192332,1,A03,,210414055249,460|0|25FC|104C,4.18,100,000F,0,A,2,9,22.643175,114.018150*75")); -- cgit v1.2.3 From 3952b3445d96d91f87d6a427ba10a86907cb0fea Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Jun 2023 22:43:06 -0700 Subject: Fix Xexun2 wifi signal --- src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java index 46e3dd118..0e3c44e12 100644 --- a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java @@ -156,7 +156,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { for (int j = 0; j < wifiCount; j++) { String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); network.addWifiAccessPoint(WifiAccessPoint.from( - mac.substring(0, mac.length() - 1), buf.readUnsignedByte())); + mac.substring(0, mac.length() - 1), buf.readByte())); } } if (BitUtil.check(positionMask, 2)) { -- cgit v1.2.3 From bc99846b0c88ac41b96744edd23ef254f492c0b7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Jun 2023 23:01:42 -0700 Subject: Support HWDECO fuel sensor --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 48 ++++++++++++++++++++++ .../protocol/Gl200TextProtocolDecoderTest.java | 4 ++ 2 files changed, 52 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 0135e78b7..bcff1c5b2 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -15,7 +15,9 @@ */ package org.traccar.protocol; +import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.DataConverter; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -368,6 +370,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .text("$").optional() .compile(); + private static final Pattern PATTERN_DTT = new PatternBuilder() + .text("+RESP:GTDTT,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,,,") // device name + .number("d,") // data type + .number("d+,") // data length + .number("(x+),") // data + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private static final Pattern PATTERN = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GT...,") .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version @@ -1165,6 +1182,34 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private Object decodeDtt(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_DTT, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + getLastLocation(position, null); + + /* + Ecuatrack +COMB,0,94.0,-1.0,,,HDC + */ + + String data = Unpooled.wrappedBuffer(DataConverter.parseHex(parser.next())) + .toString(StandardCharsets.US_ASCII); + if (data.contains("COMB")) { + String[] values = data.split(","); + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[2])); + } else { + position.set(Position.KEY_RESULT, data); + } + + decodeDeviceTime(position, parser); + + return position; + } + private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) { Parser parser = new Parser(PATTERN, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1359,6 +1404,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { case "DAR": result = decodeDar(channel, remoteAddress, sentence); break; + case "DTT": + result = decodeDtt(channel, remoteAddress, sentence); + break; default: result = decodeOther(channel, remoteAddress, sentence, type); break; diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index a73127546..760671cd9 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+RESP:GTDTT,410502,864802030541621,,,,1,35,45637561747261636b0d0a434f4d422c302c39342e302c2d312e302c2c2c4844430d0a,20230421034626,EA2E$"), + Position.KEY_FUEL_LEVEL, 94.0); + verifyNull(decoder, buffer( "+RESP:GTFRI,5E0100,862061048023666,,,12940,10,1,1,0.0,97,179.8,-90.366478,38.735379,20230616183231,0310,0410,6709,03ADF710,00,6223.7,,,,,110000,,,,202306161834$")); -- cgit v1.2.3 From a19356db10b62592a565d5a073ee989e299a0aa1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Jun 2023 23:04:50 -0700 Subject: Remove sample data comment --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index bcff1c5b2..a0e217165 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1191,11 +1191,6 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); - /* - Ecuatrack -COMB,0,94.0,-1.0,,,HDC - */ - String data = Unpooled.wrappedBuffer(DataConverter.parseHex(parser.next())) .toString(StandardCharsets.US_ASCII); if (data.contains("COMB")) { -- cgit v1.2.3 From 37564d458bb9d4bca9f1634bbe07e1102e0221cd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jul 2023 07:56:59 -0700 Subject: No override for API path --- src/main/java/org/traccar/web/OverrideFilter.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java index 70eb80a67..6d20789f2 100644 --- a/src/main/java/org/traccar/web/OverrideFilter.java +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -45,6 +45,11 @@ public class OverrideFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + if (((HttpServletRequest) request).getServletPath().startsWith("/api")) { + chain.doFilter(request, response); + return; + } + ResponseWrapper wrappedResponse = new ResponseWrapper((HttpServletResponse) response); chain.doFilter(request, wrappedResponse); -- cgit v1.2.3 From 7c5df536074e850f8f9e35775ca94fd04c3cdd3a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jul 2023 13:32:03 -0700 Subject: Configurable API timeout --- src/main/java/org/traccar/config/Keys.java | 8 ++++++++ src/main/java/org/traccar/web/ThrottlingFilter.java | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 04bf10fe7..e171511e6 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -738,6 +738,14 @@ public final class Keys { "web.maxRequestsPerSec", List.of(KeyType.CONFIG)); + /** + * Maximum API request duration in seconds. + */ + public static final ConfigKey WEB_MAX_REQUEST_SECONDS = new IntegerConfigKey( + "web.maxRequestSec", + List.of(KeyType.CONFIG), + 600); + /** * Sanitize all strings returned via API. This is needed to fix XSS issues in the old web interface. New React-based * interface doesn't require this. diff --git a/src/main/java/org/traccar/web/ThrottlingFilter.java b/src/main/java/org/traccar/web/ThrottlingFilter.java index 054af652f..6d2328562 100644 --- a/src/main/java/org/traccar/web/ThrottlingFilter.java +++ b/src/main/java/org/traccar/web/ThrottlingFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -39,6 +39,7 @@ public class ThrottlingFilter extends DoSFilter { if (config.hasKey(Keys.WEB_MAX_REQUESTS_PER_SECOND)) { setMaxRequestsPerSec(config.getInteger(Keys.WEB_MAX_REQUESTS_PER_SECOND)); } + setMaxRequestMs(config.getInteger(Keys.WEB_MAX_REQUEST_SECONDS) * 1000L); } @Override -- cgit v1.2.3 From cad2b8497c7cbd2cde4e50ec1ce2af1ceb37d02c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jul 2023 14:57:03 -0700 Subject: Support XML-based SMS APIs --- src/main/java/org/traccar/sms/HttpSmsClient.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/sms/HttpSmsClient.java b/src/main/java/org/traccar/sms/HttpSmsClient.java index 683022967..b4271a6f2 100644 --- a/src/main/java/org/traccar/sms/HttpSmsClient.java +++ b/src/main/java/org/traccar/sms/HttpSmsClient.java @@ -57,7 +57,10 @@ public class HttpSmsClient implements SmsManager { } } template = config.getString(Keys.SMS_HTTP_TEMPLATE).trim(); - if (template.charAt(0) == '{' || template.charAt(0) == '[') { + if (template.charAt(0) == '<') { + encode = false; + mediaType = MediaType.APPLICATION_XML_TYPE; + } else if (template.charAt(0) == '{' || template.charAt(0) == '[') { encode = false; mediaType = MediaType.APPLICATION_JSON_TYPE; } else { -- cgit v1.2.3 From 914cc6e85ba8696727edff2d8a600ae695bc410d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jul 2023 16:04:07 -0700 Subject: Add calendar based filtering --- schema/changelog-5.9.xml | 27 +++++++++++++++++++ schema/changelog-master.xml | 1 + .../traccar/api/security/PermissionsService.java | 12 ++++----- .../java/org/traccar/handler/FilterHandler.java | 12 +++++++-- src/main/java/org/traccar/model/Device.java | 16 ++++++++++-- src/main/java/org/traccar/model/Geofence.java | 16 ++++++++++-- src/main/java/org/traccar/model/Notification.java | 14 +++++++++- src/main/java/org/traccar/model/Report.java | 16 ++++++++++-- src/main/java/org/traccar/model/Schedulable.java | 22 ++++++++++++++++ .../java/org/traccar/model/ScheduledModel.java | 30 ---------------------- .../org/traccar/session/cache/CacheManager.java | 27 ++++++++++--------- 11 files changed, 136 insertions(+), 57 deletions(-) create mode 100644 schema/changelog-5.9.xml create mode 100644 src/main/java/org/traccar/model/Schedulable.java delete mode 100644 src/main/java/org/traccar/model/ScheduledModel.java diff --git a/schema/changelog-5.9.xml b/schema/changelog-5.9.xml new file mode 100644 index 000000000..50a3d3aaa --- /dev/null +++ b/schema/changelog-5.9.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index dd2bcc8a7..331d5ec78 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -39,5 +39,6 @@ + diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index 18a376601..38bf48f30 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -24,7 +24,7 @@ import org.traccar.model.Group; import org.traccar.model.GroupedModel; import org.traccar.model.ManagedUser; import org.traccar.model.Notification; -import org.traccar.model.ScheduledModel; +import org.traccar.model.Schedulable; import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.model.UserRestrictions; @@ -137,13 +137,13 @@ public class PermissionsService { } } } - if (object instanceof ScheduledModel) { - ScheduledModel after = ((ScheduledModel) object); + if (object instanceof Schedulable) { + Schedulable after = ((Schedulable) object); if (after.getCalendarId() > 0) { - ScheduledModel before = null; + Schedulable before = null; if (!addition) { before = storage.getObject(after.getClass(), new Request( - new Columns.Include("calendarId"), new Condition.Equals("id", after.getId()))); + new Columns.Include("calendarId"), new Condition.Equals("id", object.getId()))); } if (before == null || before.getCalendarId() != after.getCalendarId()) { checkPermission(Calendar.class, userId, after.getCalendarId()); @@ -156,7 +156,7 @@ public class PermissionsService { Notification before = null; if (!addition) { before = storage.getObject(after.getClass(), new Request( - new Columns.Include("commandId"), new Condition.Equals("id", after.getId()))); + new Columns.Include("commandId"), new Condition.Equals("id", object.getId()))); } if (before == null || before.getCommandId() != after.getCommandId()) { checkPermission(Command.class, userId, after.getCommandId()); diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 2623c3486..028e4cd09 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -25,6 +25,7 @@ import org.traccar.config.Keys; import org.traccar.database.StatisticsManager; import org.traccar.helper.UnitsConverter; import org.traccar.helper.model.AttributeUtil; +import org.traccar.model.Calendar; import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; @@ -259,9 +260,16 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { } } + Device device = cacheManager.getObject(Device.class, deviceId); + if (device.getCalendarId() > 0) { + Calendar calendar = cacheManager.getObject(Calendar.class, device.getCalendarId()); + if (!calendar.checkMoment(position.getFixTime())) { + filterType.append("Calendar "); + } + } + if (filterType.length() > 0) { - String uniqueId = cacheManager.getObject(Device.class, deviceId).getUniqueId(); - LOGGER.info("Position filtered by {}filters from device: {}", filterType, uniqueId); + LOGGER.info("Position filtered by {}filters from device: {}", filterType, device.getUniqueId()); return true; } diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index b7cffac49..2c582328e 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -22,7 +22,19 @@ import org.traccar.storage.StorageName; import java.util.Date; @StorageName("tc_devices") -public class Device extends GroupedModel implements Disableable { +public class Device extends GroupedModel implements Disableable, Schedulable { + + private long calendarId; + + @Override + public long getCalendarId() { + return calendarId; + } + + @Override + public void setCalendarId(long calendarId) { + this.calendarId = calendarId; + } private String name; diff --git a/src/main/java/org/traccar/model/Geofence.java b/src/main/java/org/traccar/model/Geofence.java index 9259028fb..ca6293651 100644 --- a/src/main/java/org/traccar/model/Geofence.java +++ b/src/main/java/org/traccar/model/Geofence.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -26,7 +26,19 @@ import org.traccar.storage.StorageName; import java.text.ParseException; @StorageName("tc_geofences") -public class Geofence extends ScheduledModel { +public class Geofence extends ExtendedModel implements Schedulable { + + private long calendarId; + + @Override + public long getCalendarId() { + return calendarId; + } + + @Override + public void setCalendarId(long calendarId) { + this.calendarId = calendarId; + } private String name; diff --git a/src/main/java/org/traccar/model/Notification.java b/src/main/java/org/traccar/model/Notification.java index b6a6e4cf5..6dcd9c9de 100644 --- a/src/main/java/org/traccar/model/Notification.java +++ b/src/main/java/org/traccar/model/Notification.java @@ -24,7 +24,19 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.storage.StorageName; @StorageName("tc_notifications") -public class Notification extends ScheduledModel { +public class Notification extends ExtendedModel implements Schedulable { + + private long calendarId; + + @Override + public long getCalendarId() { + return calendarId; + } + + @Override + public void setCalendarId(long calendarId) { + this.calendarId = calendarId; + } private boolean always; diff --git a/src/main/java/org/traccar/model/Report.java b/src/main/java/org/traccar/model/Report.java index 1556ecc9e..2ee7ae288 100644 --- a/src/main/java/org/traccar/model/Report.java +++ b/src/main/java/org/traccar/model/Report.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -18,7 +18,19 @@ package org.traccar.model; import org.traccar.storage.StorageName; @StorageName("tc_reports") -public class Report extends ScheduledModel { +public class Report extends ExtendedModel implements Schedulable { + + private long calendarId; + + @Override + public long getCalendarId() { + return calendarId; + } + + @Override + public void setCalendarId(long calendarId) { + this.calendarId = calendarId; + } private String type; diff --git a/src/main/java/org/traccar/model/Schedulable.java b/src/main/java/org/traccar/model/Schedulable.java new file mode 100644 index 000000000..331e77583 --- /dev/null +++ b/src/main/java/org/traccar/model/Schedulable.java @@ -0,0 +1,22 @@ +/* + * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@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.model; + +public interface Schedulable { + long getCalendarId(); + void setCalendarId(long calendarId); +} diff --git a/src/main/java/org/traccar/model/ScheduledModel.java b/src/main/java/org/traccar/model/ScheduledModel.java deleted file mode 100644 index 9e6a4b9a6..000000000 --- a/src/main/java/org/traccar/model/ScheduledModel.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@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.model; - -public class ScheduledModel extends ExtendedModel { - - private long calendarId; - - public long getCalendarId() { - return calendarId; - } - - public void setCalendarId(long calendarId) { - this.calendarId = calendarId; - } -} diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 9d2350012..24abd7347 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -31,7 +31,7 @@ import org.traccar.model.GroupedModel; import org.traccar.model.Maintenance; import org.traccar.model.Notification; import org.traccar.model.Position; -import org.traccar.model.ScheduledModel; +import org.traccar.model.Schedulable; import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.storage.Storage; @@ -244,8 +244,8 @@ public class CacheManager implements BroadcastInterface { if (((GroupedModel) before).getGroupId() != ((GroupedModel) object).getGroupId()) { invalidate = true; } - } else if (object instanceof ScheduledModel) { - if (((ScheduledModel) before).getCalendarId() != ((ScheduledModel) object).getCalendarId()) { + } else if (object instanceof Schedulable) { + if (((Schedulable) before).getCalendarId() != ((Schedulable) object).getCalendarId()) { invalidate = true; } } @@ -308,6 +308,12 @@ public class CacheManager implements BroadcastInterface { new Columns.All(), new Condition.Equals("id", deviceId))); if (device != null) { addObject(deviceId, device); + if (device.getCalendarId() > 0) { + var calendar = storage.getObject(Calendar.class, new Request( + new Columns.All(), new Condition.Equals("id", device.getCalendarId()))); + links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId()); + addObject(deviceId, calendar); + } int groupDepth = 0; long groupId = device.getGroupId(); @@ -326,13 +332,12 @@ public class CacheManager implements BroadcastInterface { links.put(clazz, objects.stream().map(BaseModel::getId).collect(Collectors.toSet())); for (var object : objects) { addObject(deviceId, object); - if (object instanceof ScheduledModel) { - var scheduled = (ScheduledModel) object; + if (object instanceof Schedulable) { + var scheduled = (Schedulable) object; if (scheduled.getCalendarId() > 0) { var calendar = storage.getObject(Calendar.class, new Request( new Columns.All(), new Condition.Equals("id", scheduled.getCalendarId()))); - links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()) - .add(calendar.getId()); + links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId()); addObject(deviceId, calendar); } } @@ -350,14 +355,12 @@ public class CacheManager implements BroadcastInterface { .filter(Notification::getAlways) .collect(Collectors.toList()); for (var notification : notifications) { - links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()) - .add(notification.getId()); + links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()).add(notification.getId()); addObject(deviceId, notification); if (notification.getCalendarId() > 0) { var calendar = storage.getObject(Calendar.class, new Request( new Columns.All(), new Condition.Equals("id", notification.getCalendarId()))); - links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()) - .add(calendar.getId()); + links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId()); addObject(deviceId, calendar); } } -- cgit v1.2.3 From 18ee50d2b0ddd75328a1c43fff21be5a4f11910d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jul 2023 16:11:52 -0700 Subject: Fix unit tests --- src/test/java/org/traccar/handler/FilterHandlerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/org/traccar/handler/FilterHandlerTest.java b/src/test/java/org/traccar/handler/FilterHandlerTest.java index 14037f723..36bb84f19 100644 --- a/src/test/java/org/traccar/handler/FilterHandlerTest.java +++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java @@ -29,6 +29,7 @@ public class FilterHandlerTest extends BaseTest { when(config.getBoolean(Keys.FILTER_ENABLE)).thenReturn(true); var cacheManager = mock(CacheManager.class); when(cacheManager.getConfig()).thenReturn(config); + when(cacheManager.getObject(any(), anyLong())).thenReturn(mock(Device.class)); passingHandler = new FilterHandler(config, cacheManager, null, null); } -- cgit v1.2.3 From d4c204914f907f7bbdf34a965500797b03fafdf8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jul 2023 21:52:41 -0700 Subject: Decode R31 heartbeat data --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 7 +++++++ src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 7013533bc..38c2219f8 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -828,6 +828,11 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } } + if (type == MSG_STATUS && variant == Variant.VXT01) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + } + if (type == MSG_GPS_LBS_1) { if (variant == Variant.GT06E_CARD) { position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); @@ -1408,6 +1413,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.VXT01; } else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_1 && length == 0x24) { variant = Variant.VXT01; + } else if (header == 0x7878 && type == MSG_STATUS && length == 0x0a) { + variant = Variant.VXT01; } else if (header == 0x7878 && type == MSG_LBS_MULTIPLE_3 && length == 0x31) { variant = Variant.WANWAY_S20; } else if (header == 0x7878 && type == MSG_LBS_MULTIPLE_3 && length == 0x2e) { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 8f2c97f86..937c7eca1 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78780a130604ea04000006bc8a0d0a"), + Position.KEY_POWER, 0.0); + verifyAttributes(decoder, binary( "797900849404414c4d313d43353b414c4d323d43433b414c4d333d35433b535441313d43303b4459443d30313b534f533d303133323838333730302c2c3b43454e5445523d303133323838333730303b46454e43453d46656e63652c4f46462c302c302e3030303030302c302e3030303030302c3330302c494e206f72204f55542c313b00b79d120d0a")); -- cgit v1.2.3 From 957a68d4a378c0f9d5000bc00599427fd78e663d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Jul 2023 09:12:06 -0700 Subject: Reorganize GL200 text decoder --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 738 ++++++++++----------- 1 file changed, 369 insertions(+), 369 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index a0e217165..e33093d6f 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -70,372 +70,6 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .text("$").optional() .compile(); - private static final Pattern PATTERN_INF = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTINF,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:[0-9A-Z]{17},)?") // vin - .expression("(?:[^,]+)?,") // device name - .number("(xx),") // state - .expression("(?:[0-9Ff]{20})?,") // iccid - .number("(d{1,2}),") // rssi - .number("d{1,2},") - .expression("[01]{1,2},") // external power - .number("([d.]+)?,") // odometer or external power - .number("d*,") // backup battery or lightness - .number("(d+.d+),") // battery - .expression("([01]),") // charging - .number("(?:d),") // led - .number("(?:d)?,") // gps on need - .number("(?:d)?,") // gps antenna type - .number("(?:d)?,").optional() // gps antenna state - .number("d{14},") // last fix time - .groupBegin() - .number("(d+),") // battery percentage - .number("[d.]*,") // flash type / power - .number("(-?[d.]+)?,,,") // temperature - .or() - .expression("(?:[01])?,").optional() // pin15 mode - .number("(d+)?,") // adc1 - .number("(d+)?,").optional() // adc2 - .number("(xx)?,") // digital input - .number("(xx)?,") // digital output - .number("[-+]dddd,") // timezone - .expression("[01],") // daylight saving - .or() - .any() - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_VER = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTVER,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .expression("([^,]*),") // device type - .number("(xxxx),") // firmware version - .number("(xxxx),") // hardware version - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_LOCATION = new PatternBuilder() - .number("(d{1,2}.?d?)?,") // hdop - .number("(d{1,3}.d)?,") // speed - .number("(d{1,3}.?d?)?,") // course - .number("(-?d{1,5}.d)?,") // altitude - .number("(-?d{1,3}.d{6})?,") // longitude - .number("(-?d{1,2}.d{6})?,") // latitude - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(d+)?,") // mcc - .number("(d+)?,") // mnc - .groupBegin() - .number("(d+),") // lac - .number("(d+),") // cid - .or() - .number("(x+)?,") // lac - .number("(x+)?,") // cid - .groupEnd() - .number("(?:d+|(d+.d))?,") // rssi / odometer - .compile(); - - private static final Pattern PATTERN_OBD = new PatternBuilder() - .text("+RESP:GTOBD,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:[0-9A-Z]{17})?,") // vin - .expression("[^,]{0,20},") // device name - .expression("[01],") // report type - .number("x{1,8},") // report mask - .expression("(?:[0-9A-Z]{17})?,") // vin - .number("[01],") // obd connect - .number("(?:d{1,5})?,") // obd voltage - .number("(?:x{8})?,") // support pids - .number("(d{1,5})?,") // engine rpm - .number("(d{1,3})?,") // speed - .number("(-?d{1,3})?,") // coolant temp - .number("(d+.?d*|Inf|NaN)?,") // fuel consumption - .number("(d{1,5})?,") // dtcs cleared distance - .number("(?:d{1,5})?,") - .expression("([01])?,") // obd connect - .number("(d{1,3})?,") // number of dtcs - .number("(x*),") // dtcs - .number("(d{1,3})?,") // throttle - .number("(?:d{1,3})?,") // engine load - .number("(d{1,3})?,") // fuel level - .expression("(?:[0-9A],)?") // obd protocol - .number("(d+),") // odometer - .expression(PATTERN_LOCATION.pattern()) - .number("(d{1,7}.d)?,") // odometer - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_FRI = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:([0-9A-Z]{17}),)?") // vin - .expression("[^,]*,") // device name - .number("(d+)?,") // power - .number("(d{1,2}),").optional() // report type - .number("d{1,2},").optional() // count - .number("d*,").optional() // reserved - .number("(d+),").optional() // battery - .expression("((?:") - .expression(PATTERN_LOCATION.pattern()) - .expression(")+)") - .groupBegin() - .number("d{1,2},,") - .number("(d{1,3}),") // battery - .number("[01],") // mode - .number("(?:[01])?,") // motion - .number("(?:-?d{1,2}.d)?,") // temperature - .or() - .number("(d{1,7}.d)?,") // odometer - .number("(d{5}:dd:dd)?,") // hour meter - .number("(x+)?,") // adc 1 - .number("(x+)?,") // adc 2 - .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status - .number("(d+)?,") // rpm - .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption - .number("(d+)?,") // fuel level - .or() - .number("(-?d),") // rssi - .number("(d{1,3}),") // battery - .or() - .number("(d{1,7}.d)?,").optional() // odometer - .number("(d{1,3})?,") // battery - .groupEnd() - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_ERI = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTERI,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(x{8}),") // mask - .number("(d+)?,") // power - .number("d{1,2},") // report type - .number("d{1,2},") // count - .expression("((?:") - .expression(PATTERN_LOCATION.pattern()) - .expression(")+)") - .groupBegin() - .number("(d{1,7}.d)?,") // odometer - .number("(d{5}:dd:dd)?,") // hour meter - .number("(x+)?,") // adc 1 - .number("(x+)?,").optional() // adc 2 - .groupBegin() - .number("(x+)?,") // adc 3 - .number("(xx),") // inputs - .number("(xx),") // outputs - .or() - .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status - .groupEnd() - .expression("(.*)") // additional data - .or() - .number("d*,,") - .number("(d+),") // battery - .any() - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_IGN = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTIG[NF],") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("d+,") // ignition off duration - .expression(PATTERN_LOCATION.pattern()) - .number("(d{5}:dd:dd)?,") // hour meter - .number("(d{1,7}.d)?,") // odometer - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_LSW = new PatternBuilder() - .text("+RESP:").expression("GT[LT]SW,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("[01],") // type - .number("([01]),") // state - .expression(PATTERN_LOCATION.pattern()) - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_IDA = new PatternBuilder() - .text("+RESP:GTIDA,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,,") // device name - .number("([^,]+),") // rfid - .expression("[01],") // report type - .number("1,") // count - .expression(PATTERN_LOCATION.pattern()) - .number("(d+.d),") // odometer - .text(",,,,") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_WIF = new PatternBuilder() - .text("+RESP:GTWIF,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(d+),") // count - .number("((?:x{12},-?d+,,,,)+),,,,") // wifi - .number("(d{1,3}),") // battery - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_GSM = new PatternBuilder() - .text("+RESP:GTGSM,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:STR|CTN|NMR|RTL),") // fix type - .expression("(.*)") // cells - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_PNA = new PatternBuilder() - .text("+RESP:GT").expression("P[NF]A,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_DAR = new PatternBuilder() - .text("+RESP:GTDAR,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(d),") // warning type - .number("(d{1,2}),,,") // fatigue degree - .expression(PATTERN_LOCATION.pattern()) - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_DTT = new PatternBuilder() - .text("+RESP:GTDTT,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,,,") // device name - .number("d,") // data type - .number("d+,") // data length - .number("(x+),") // data - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("d*,") - .number("(x{1,2}),") // report type - .number("d{1,2},") // count - .number("d*,").optional() // reserved - .expression(PATTERN_LOCATION.pattern()) - .groupBegin() - .number("(?:(d{1,7}.d)|0)?,").optional() // odometer - .number("(d{1,3})?,") // battery - .or() - .number("(d{1,7}.d)?,") // odometer - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_BASIC = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF)").text(":") - .expression("GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version - .number("(d{15}|x{14}),") // imei - .any() - .text(",") - .number("(d{1,2})?,") // hdop - .number("(d{1,3}.d)?,") // speed - .number("(d{1,3})?,") // course - .number("(-?d{1,5}.d)?,") // altitude - .number("(-?d{1,3}.d{6})?,") // longitude - .number("(-?d{1,2}.d{6})?,") // latitude - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(x+),") // lac - .number("(x+),").optional(4) // cell - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - private Object decodeAck(Channel channel, SocketAddress remoteAddress, String sentence, String type) { Parser parser = new Parser(PATTERN_ACK, sentence); if (parser.matches()) { @@ -487,13 +121,54 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private Long parseHours(String hoursString) { if (hoursString != null) { String[] hours = hoursString.split(":"); - return (long) (Integer.parseInt(hours[0]) * 3600 - + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0) + return (Integer.parseInt(hours[0]) * 3600L + + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60L : 0) + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000; } return null; } + private static final Pattern PATTERN_INF = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTINF,") + .number("[0-9A-Z]{2}xxxx,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:[0-9A-Z]{17},)?") // vin + .expression("(?:[^,]+)?,") // device name + .number("(xx),") // state + .expression("(?:[0-9Ff]{20})?,") // iccid + .number("(d{1,2}),") // rssi + .number("d{1,2},") + .expression("[01]{1,2},") // external power + .number("([d.]+)?,") // odometer or external power + .number("d*,") // backup battery or lightness + .number("(d+.d+),") // battery + .expression("([01]),") // charging + .number("(?:d),") // led + .number("(?:d)?,") // gps on need + .number("(?:d)?,") // gps antenna type + .number("(?:d)?,").optional() // gps antenna state + .number("d{14},") // last fix time + .groupBegin() + .number("(d+),") // battery percentage + .number("[d.]*,") // flash type / power + .number("(-?[d.]+)?,,,") // temperature + .or() + .expression("(?:[01])?,").optional() // pin15 mode + .number("(d+)?,") // adc1 + .number("(d+)?,").optional() // adc2 + .number("(xx)?,") // digital input + .number("(xx)?,") // digital output + .number("[-+]dddd,") // timezone + .expression("[01],") // daylight saving + .or() + .any() + .groupEnd() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(xxxx)") // counter + .text("$").optional() + .compile(); + private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_INF, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -554,6 +229,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_VER = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTVER,") + .number("[0-9A-Z]{2}xxxx,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .expression("([^,]*),") // device type + .number("(xxxx),") // firmware version + .number("(xxxx),") // hardware version + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(xxxx)") // counter + .text("$").optional() + .compile(); + private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_VER, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -574,6 +263,28 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { parser.skip(19); } + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .number("(d{1,2}.?d?)?,") // hdop + .number("(d{1,3}.d)?,") // speed + .number("(d{1,3}.?d?)?,") // course + .number("(-?d{1,5}.d)?,") // altitude + .number("(-?d{1,3}.d{6})?,") // longitude + .number("(-?d{1,2}.d{6})?,") // latitude + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(d+)?,") // mcc + .number("(d+)?,") // mnc + .groupBegin() + .number("(d+),") // lac + .number("(d+),") // cid + .or() + .number("(x+)?,") // lac + .number("(x+)?,") // cid + .groupEnd() + .number("(?:d+|(d+.d))?,") // rssi / odometer + .compile(); + private void decodeLocation(Position position, Parser parser) { Double hdop = parser.nextDouble(); position.setValid(hdop == null || hdop > 0); @@ -608,6 +319,41 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } } + private static final Pattern PATTERN_OBD = new PatternBuilder() + .text("+RESP:GTOBD,") + .number("[0-9A-Z]{2}xxxx,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:[0-9A-Z]{17})?,") // vin + .expression("[^,]{0,20},") // device name + .expression("[01],") // report type + .number("x{1,8},") // report mask + .expression("(?:[0-9A-Z]{17})?,") // vin + .number("[01],") // obd connect + .number("(?:d{1,5})?,") // obd voltage + .number("(?:x{8})?,") // support pids + .number("(d{1,5})?,") // engine rpm + .number("(d{1,3})?,") // speed + .number("(-?d{1,3})?,") // coolant temp + .number("(d+.?d*|Inf|NaN)?,") // fuel consumption + .number("(d{1,5})?,") // dtcs cleared distance + .number("(?:d{1,5})?,") + .expression("([01])?,") // obd connect + .number("(d{1,3})?,") // number of dtcs + .number("(x*),") // dtcs + .number("(d{1,3})?,") // throttle + .number("(?:d{1,3})?,") // engine load + .number("(d{1,3})?,") // fuel level + .expression("(?:[0-9A],)?") // obd protocol + .number("(d+),") // odometer + .expression(PATTERN_LOCATION.pattern()) + .number("(d{1,7}.d)?,") // odometer + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_OBD, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -858,6 +604,51 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } } + private static final Pattern PATTERN_FRI = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GT...,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:([0-9A-Z]{17}),)?") // vin + .expression("[^,]*,") // device name + .number("(d+)?,") // power + .number("(d{1,2}),").optional() // report type + .number("d{1,2},").optional() // count + .number("d*,").optional() // reserved + .number("(d+),").optional() // battery + .expression("((?:") + .expression(PATTERN_LOCATION.pattern()) + .expression(")+)") + .groupBegin() + .number("d{1,2},,") + .number("(d{1,3}),") // battery + .number("[01],") // mode + .number("(?:[01])?,") // motion + .number("(?:-?d{1,2}.d)?,") // temperature + .or() + .number("(d{1,7}.d)?,") // odometer + .number("(d{5}:dd:dd)?,") // hour meter + .number("(x+)?,") // adc 1 + .number("(x+)?,") // adc 2 + .number("(d{1,3})?,") // battery + .number("(?:(xx)(xx)(xx))?,") // device status + .number("(d+)?,") // rpm + .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption + .number("(d+)?,") // fuel level + .or() + .number("(-?d),") // rssi + .number("(d{1,3}),") // battery + .or() + .number("(d{1,7}.d)?,").optional() // odometer + .number("(d{1,3})?,") // battery + .groupEnd() + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeFri(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_FRI, sentence); if (!parser.matches()) { @@ -938,6 +729,44 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return positions; } + private static final Pattern PATTERN_ERI = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTERI,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(x{8}),") // mask + .number("(d+)?,") // power + .number("d{1,2},") // report type + .number("d{1,2},") // count + .expression("((?:") + .expression(PATTERN_LOCATION.pattern()) + .expression(")+)") + .groupBegin() + .number("(d{1,7}.d)?,") // odometer + .number("(d{5}:dd:dd)?,") // hour meter + .number("(x+)?,") // adc 1 + .number("(x+)?,").optional() // adc 2 + .groupBegin() + .number("(x+)?,") // adc 3 + .number("(xx),") // inputs + .number("(xx),") // outputs + .or() + .number("(d{1,3})?,") // battery + .number("(?:(xx)(xx)(xx))?,") // device status + .groupEnd() + .expression("(.*)") // additional data + .or() + .number("d*,,") + .number("(d+),") // battery + .any() + .groupEnd() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeEri(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_ERI, sentence); if (!parser.matches()) { @@ -1041,6 +870,22 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return positions; } + private static final Pattern PATTERN_IGN = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTIG[NF],") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d+,") // ignition off duration + .expression(PATTERN_LOCATION.pattern()) + .number("(d{5}:dd:dd)?,") // hour meter + .number("(d{1,7}.d)?,") // odometer + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeIgn(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_IGN, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1059,6 +904,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_LSW = new PatternBuilder() + .text("+RESP:").expression("GT[LT]SW,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("[01],") // type + .number("([01]),") // state + .expression(PATTERN_LOCATION.pattern()) + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeLsw(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_LSW, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1075,6 +935,24 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_IDA = new PatternBuilder() + .text("+RESP:GTIDA,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,,") // device name + .number("([^,]+),") // rfid + .expression("[01],") // report type + .number("1,") // count + .expression(PATTERN_LOCATION.pattern()) + .number("(d+.d),") // odometer + .text(",,,,") + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeIda(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_IDA, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1093,6 +971,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_WIF = new PatternBuilder() + .text("+RESP:GTWIF,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(d+),") // count + .number("((?:x{12},-?d+,,,,)+),,,,") // wifi + .number("(d{1,3}),") // battery + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeWif(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_WIF, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1119,6 +1012,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_GSM = new PatternBuilder() + .text("+RESP:GTGSM,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:STR|CTN|NMR|RTL),") // fix type + .expression("(.*)") // cells + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeGsm(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_GSM, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1145,6 +1051,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_PNA = new PatternBuilder() + .text("+RESP:GT").expression("P[NF]A,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodePna(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_PNA, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1159,6 +1077,22 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_DAR = new PatternBuilder() + .text("+RESP:GTDAR,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(d),") // warning type + .number("(d{1,2}),,,") // fatigue degree + .expression(PATTERN_LOCATION.pattern()) + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeDar(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_DAR, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1182,6 +1116,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_DTT = new PatternBuilder() + .text("+RESP:GTDTT,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,,,") // device name + .number("d,") // data type + .number("d+,") // data length + .number("(x+),") // data + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeDtt(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_DTT, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1205,6 +1154,29 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GT...,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d*,") + .number("(x{1,2}),") // report type + .number("d{1,2},") // count + .number("d*,").optional() // reserved + .expression(PATTERN_LOCATION.pattern()) + .groupBegin() + .number("(?:(d{1,7}.d)|0)?,").optional() // odometer + .number("(d{1,3})?,") // battery + .or() + .number("(d{1,7}.d)?,") // odometer + .groupEnd() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) { Parser parser = new Parser(PATTERN, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1255,6 +1227,34 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_BASIC = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF)").text(":") + .expression("GT...,") + .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version + .number("(d{15}|x{14}),") // imei + .any() + .text(",") + .number("(d{1,2})?,") // hdop + .number("(d{1,3}.d)?,") // speed + .number("(d{1,3})?,") // course + .number("(-?d{1,5}.d)?,") // altitude + .number("(-?d{1,3}.d{6})?,") // longitude + .number("(-?d{1,2}.d{6})?,") // latitude + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(x+),") // lac + .number("(x+),").optional(4) // cell + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeBasic(Channel channel, SocketAddress remoteAddress, String sentence, String type) { Parser parser = new Parser(PATTERN_BASIC, sentence); Position position = initPosition(parser, channel, remoteAddress); -- cgit v1.2.3 From a8a06ffd494fc7161ca0edca39ae35be865a383f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Jul 2023 09:41:32 -0700 Subject: Support GV350M accessories --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 104 +++++++++++++++++++++ .../protocol/Gl200TextProtocolDecoderTest.java | 8 ++ 2 files changed, 112 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index e33093d6f..bfd0a4cbb 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1154,6 +1154,104 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_BAA = new PatternBuilder() + .text("+RESP:GTBAA,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("x+,") // index + .number("d,") // accessory type + .number("d,") // accessory model + .number("x+,") // alarm type + .number("(x{4}),") // append mask + .expression("((?:[^,]+,){0,6})") // accessory optionals + .expression(PATTERN_LOCATION.pattern()) + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeBaa(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_BAA, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + int mask = parser.nextHexInt(); + String[] values = parser.next().split(","); + int index = 0; + if (BitUtil.check(mask, 0)) { + position.set("accessoryName", values[index++]); + } + if (BitUtil.check(mask, 1)) { + position.set("accessoryMac", values[index++]); + } + if (BitUtil.check(mask, 2)) { + position.set("accessoryStatus", Integer.parseInt(values[index++])); + } + if (BitUtil.check(mask, 3)) { + position.set("accessoryVoltage", Integer.parseInt(values[index++]) * 0.001); + } + if (BitUtil.check(mask, 4)) { + position.set("accessoryTemp", Integer.parseInt(values[index++])); + } + if (BitUtil.check(mask, 5)) { + position.set("accessoryHumidity", Integer.parseInt(values[index])); + } + + decodeLocation(position, parser); + + decodeDeviceTime(position, parser); + + return position; + } + + private static final Pattern PATTERN_BID = new PatternBuilder() + .text("+RESP:GTBID,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d,") // count + .number("d,") // accessory model + .number("(x{4}),") // append mask + .expression("((?:[^,]+,){0,2})") // accessory optionals + .expression(PATTERN_LOCATION.pattern()) + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeBid(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_BID, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + int mask = parser.nextHexInt(); + String[] values = parser.next().split(","); + int index = 0; + if (BitUtil.check(mask, 1)) { + position.set("accessoryMac", values[index++]); + } + if (BitUtil.check(mask, 3)) { + position.set("accessoryVoltage", Integer.parseInt(values[index]) * 0.001); + } + + decodeLocation(position, parser); + + decodeDeviceTime(position, parser); + + return position; + } + private static final Pattern PATTERN = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GT...,") .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version @@ -1402,6 +1500,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { case "DTT": result = decodeDtt(channel, remoteAddress, sentence); break; + case "BAA": + result = decodeBaa(channel, remoteAddress, sentence); + break; + case "BID": + result = decodeBid(channel, remoteAddress, sentence); + break; default: result = decodeOther(channel, remoteAddress, sentence, type); break; diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 760671cd9..fcd2c6be4 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,14 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+RESP:GTBAA,F1040C,862599050497393,GV350M,FF,3,0,04,000A,780541256AE9,3065,0,0.0,213,2908.3,-78.691944,-0.951426,20230511173150,,,,,,20230511175001,0159$"), + "accessoryVoltage", 3.065); + + verifyAttribute(decoder, buffer( + "+RESP:GTBID,C20105,866833040163013,GV350M,1,0,000A,B80EA11FF800,2934,0,0.0,0,1506.5,-99.192686,18.932709,20221026025339,0334,0020,0232,029D4E02,,20221026181026,9F1D$"), + "accessoryVoltage", 2.934); + verifyAttribute(decoder, buffer( "+RESP:GTDTT,410502,864802030541621,,,,1,35,45637561747261636b0d0a434f4d422c302c39342e302c2d312e302c2c2c4844430d0a,20230421034626,EA2E$"), Position.KEY_FUEL_LEVEL, 94.0); -- cgit v1.2.3 From 44527107b2bd5798356d6639573d3ccea67fd3b4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 3 Jul 2023 13:54:19 -0700 Subject: Initial T622G-F9 Iridium support --- setup/default.xml | 1 + .../org/traccar/protocol/T622IridiumProtocol.java | 39 +++++++++ .../protocol/T622IridiumProtocolDecoder.java | 93 ++++++++++++++++++++++ .../protocol/T622IridiumProtocolDecoderTest.java | 20 +++++ 4 files changed, 153 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/T622IridiumProtocol.java create mode 100644 src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index e8dc7aa79..576bfcb6c 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -289,5 +289,6 @@ 5245 5246 5247 + 5248 diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocol.java b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java new file mode 100644 index 000000000..1289fe8e7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java @@ -0,0 +1,39 @@ +/* + * 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.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import javax.inject.Inject; + +public class T622IridiumProtocol extends BaseProtocol { + + @Inject + public T622IridiumProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2)); + pipeline.addLast(new T622IridiumProtocolDecoder(T622IridiumProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java new file mode 100644 index 000000000..6a81a452a --- /dev/null +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java @@ -0,0 +1,93 @@ +/* + * 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.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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; + +public class T622IridiumProtocolDecoder extends BaseProtocolDecoder { + + public T622IridiumProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // protocol revision + buf.readUnsignedShort(); // length + buf.readUnsignedByte(); // header indicator + buf.readUnsignedShort(); // header length + buf.readUnsignedInt(); // reference + + String imei = buf.readCharSequence(15, StandardCharsets.US_ASCII).toString(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + buf.readUnsignedByte(); // session status + buf.readUnsignedShort(); // originator index + buf.readUnsignedShort(); // transfer index + buf.readUnsignedInt(); // session time + buf.readUnsignedByte(); // payload indicator + buf.readUnsignedShort(); // payload length + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + position.setLatitude(buf.readIntLE() / 1000000.0); + position.setLongitude(buf.readIntLE() / 1000000.0); + position.setTime(new Date((buf.readUnsignedIntLE() + 946713600) * 1000)); + position.setValid(buf.readUnsignedByte() > 0); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + + position.setAltitude(buf.readShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); + + buf.readUnsignedByte(); // geofence + + return position; + } + +} diff --git a/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java new file mode 100644 index 000000000..4bc79fbe8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java @@ -0,0 +1,20 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class T622IridiumProtocolDecoderTest extends ProtocolTest { + + @Disabled + @Test + public void testDecode() throws Exception { + + var decoder = inject(new T622IridiumProtocolDecoder(null)); + + verifyPosition(decoder, binary( + "01003301001c2a8cef8333303034333430363735343836353000001700006461d512020011232f03a0fff1c85d0612b3f02b00000048")); + + } + +} -- cgit v1.2.3 From 5e18cb586d34aa3db0417cef9635bf1d9cae6e18 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 3 Jul 2023 21:21:38 -0700 Subject: Support GV350M CAN messages --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 25 ++++++++++++++++------ .../protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index bfd0a4cbb..911af8d73 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -400,7 +400,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); position.setDeviceId(deviceSession.getDeviceId()); - index += 1; // device name + String deviceName = values[index++]; index += 1; // report type index += 1; // canbus state long reportMask = Long.parseLong(values[index++], 16); @@ -442,11 +442,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMask, 11) && !values[index++].isEmpty()) { position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1]))); } - if (BitUtil.check(reportMask, 12)) { - position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(values[index++])); + if (BitUtil.check(reportMask, 12) && !values[index++].isEmpty()) { + position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(values[index - 1])); } - if (BitUtil.check(reportMask, 13)) { - position.set("idleHours", Double.parseDouble(values[index++])); + if (BitUtil.check(reportMask, 13) && !values[index++].isEmpty()) { + position.set("idleHours", Double.parseDouble(values[index - 1])); } if (BitUtil.check(reportMask, 14) && !values[index++].isEmpty()) { position.set("idleFuelConsumption", Double.parseDouble(values[index - 1])); @@ -472,8 +472,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) { position.set("engineOverspeed", Double.parseDouble(values[index - 1])); } - if (BitUtil.check(reportMask, 29)) { - reportMaskExt = Long.parseLong(values[index++], 16); + if ("GV350M".equals(deviceName)) { + if (BitUtil.check(reportMask, 22)) { + index += 1; // impulse distance + } + if (BitUtil.check(reportMask, 23)) { + index += 1; // gross vehicle weight + } + if (BitUtil.check(reportMask, 24)) { + index += 1; // catalyst liquid level + } + } + if (BitUtil.check(reportMask, 29) && !values[index++].isEmpty()) { + reportMaskExt = Long.parseLong(values[index - 1], 16); } if (BitUtil.check(reportMaskExt, 0) && !values[index++].isEmpty()) { position.set("adBlueLevel", Integer.parseInt(values[index - 1])); diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index fcd2c6be4..f0dd10772 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttributes(decoder, buffer( + "+RESP:GTCAN,F1040C,862599050497393,GV350M,0,0,FFFFFFFF,,1,,,,,,,,,,,,,,,,,,,,,,,0,,,1,0.0,70,2961.6,-78.691750,-0.951135,20230703191659,,,,,,20230703191659,5A4A$")); + verifyAttribute(decoder, buffer( "+RESP:GTBAA,F1040C,862599050497393,GV350M,FF,3,0,04,000A,780541256AE9,3065,0,0.0,213,2908.3,-78.691944,-0.951426,20230511173150,,,,,,20230511175001,0159$"), "accessoryVoltage", 3.065); -- cgit v1.2.3 From 8b4d3ee0b96407ad3c889bc3bb0261e5ebe60532 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 4 Jul 2023 07:25:53 -0700 Subject: Minifinder decode phone numbers --- .../org/traccar/protocol/MiniFinderProtocolDecoder.java | 16 +++++++++++++++- .../traccar/protocol/MiniFinderProtocolDecoderTest.java | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java index f2e5eb905..1fdb1ece0 100644 --- a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java @@ -143,7 +143,7 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder { } DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null || !sentence.matches("![35A-D],.*")) { + if (deviceSession == null || !sentence.matches("![345A-D],.*")) { return null; } @@ -161,6 +161,20 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder { return position; + } else if (type.equals("4")) { + + String[] values = sentence.split(","); + + getLastLocation(position, null); + + for (int i = 1; i <= 3; i++) { + if (!values[i + 1].isEmpty()) { + position.set("phone" + i, values[i + 1]); + } + } + + return position; + } else if (type.equals("5")) { String[] values = sentence.split(","); diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java index d955d8e50..712d59dc9 100644 --- a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java @@ -20,6 +20,10 @@ public class MiniFinderProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, text( "!1,123456789012345")); + verifyAttribute(decoder, text( + "!4,10,040123,,,1.0,110,0,0S,33"), + "phone1", "040123"); + verifyAttribute(decoder, text( "!5,17,V,50"), Position.KEY_BATTERY_LEVEL, 50); -- cgit v1.2.3 From 52799453e0ee9a9db3cbad58138712c8c40c458f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 4 Jul 2023 08:02:33 -0700 Subject: iStartek VT200 ACC on time --- .../org/traccar/protocol/StartekProtocolDecoder.java | 16 ++++++++++------ .../org/traccar/protocol/StartekProtocolDecoderTest.java | 4 ++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java index d08bb92a8..9c749c8d9 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -72,12 +72,10 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { .number("(x+)") // battery .expression("([^,]+)?") // adc .groupBegin() - .text(",") - .number("d,") // extended - .expression("([^,]+)?") // fuel + .number(",d+") // extended + .expression(",([^,]+)?") // fuel .groupBegin() - .text(",") - .expression("([^,]+)?") // temperature + .expression(",([^,]+)?") // temperature .groupBegin() .text(",") .groupBegin() @@ -91,9 +89,11 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { .number("(d+)?|") // instant fuel .number("(d+)[%L]").optional() // fuel level .groupEnd("?") + .number(",(d+)").optional() // hours .groupEnd("?") .groupEnd("?") .groupEnd("?") + .any() .compile(); private String decodeAlarm(int value) { @@ -224,7 +224,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { } } - if (parser.hasNextAny(6)) { + if (parser.hasNextAny(9)) { position.set(Position.KEY_RPM, parser.nextInt()); position.set(Position.KEY_ENGINE_LOAD, parser.nextInt()); position.set("airFlow", parser.nextInt()); @@ -242,6 +242,10 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); } + if (parser.hasNext()) { + position.set(Position.KEY_HOURS, parser.nextInt() * 1000L); + } + return position; } diff --git a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java index 361e6e6f2..9b1362f5d 100644 --- a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class StartekProtocolDecoderTest extends ProtocolTest { var decoder = inject(new StartekProtocolDecoder(null)); + verifyAttribute(decoder, text( + "&&s148,868703050178631,000,37,,230704040211,A,22.678565,114.046011,31,0.5,0,339,77,8,460|0|249F|0AC2620D,27,0000001D,02,00,04F2|01A1|0000|0000,129,,,,949037"), + Position.KEY_HOURS, 9490000L); + verifyAttribute(decoder, text( "&&x164,869926040743375,000,0,,220705205955,A,33.326001,44.445318,10,1.2,0,57,8,925,418|40|038C|000083CD,31,00000015,00,00,0016|016A|0000|0000,1,,,686|33||44|99|14|124|11|8D"), Position.KEY_FUEL_CONSUMPTION, 1.1); -- cgit v1.2.3 From 7d4f1fb9a037df92f9fbaa020806ed989d86b1e2 Mon Sep 17 00:00:00 2001 From: geduxas Date: Wed, 5 Jul 2023 23:32:21 +0300 Subject: Update TeltonikaProtocolDecoder.java Small fix for #5129 thought traccar expects value in kilometer. --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index c6531c790..c8e0005f9 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -252,7 +252,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(83, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_USED, b.readUnsignedInt() * 0.1)); register(84, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_LEVEL, b.readUnsignedShort() * 0.1)); register(85, fmbXXX, (p, b) -> p.set(Position.KEY_RPM, b.readUnsignedShort())); - register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt() * 0.001)); + register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt())); register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); -- cgit v1.2.3 From c12f74fea206191877d4a727547bfdb0c9b938cc Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Fri, 7 Jul 2023 08:08:48 -0400 Subject: Keep same structure as before --- .../traccar/protocol/LaipacProtocolDecoder.java | 39 +++++++++++----------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 3b654db0c..dbac159b3 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -110,26 +110,25 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private String decodeEvent(String event, Position position) { - if (event.length() != 1) { - return event; - } - - int inputStatusInt = 0; - char inputStatus = event.charAt(0); - - if (inputStatus >= 'A' && inputStatus <= 'D') { - inputStatusInt = inputStatus - 'A'; - } else if (inputStatus >= 'O' && inputStatus <= 'R') { - inputStatusInt = inputStatus - 'O' + 4; - } else { - return event; - } - - position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); - position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); - position.set(Position.PREFIX_IN + 3, inputStatusInt & 4); - - return null; + if (event.length() == 1) { + char inputStatus = event.charAt(0); + if (inputStatus >= 'A' && inputStatus <= 'D') { + int inputStatusInt = inputStatus - 'A'; + position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); + position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + position.set(Position.PREFIX_IN + 3, 0); + return null; + } else if (inputStatus >= 'O' && inputStatus <= 'R') { + int inputStatusInt = inputStatus - 'O'; + position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); + position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + position.set(Position.PREFIX_IN + 3, 1); + return null; + } + } + + return event; + } private void sendEventResponse( -- cgit v1.2.3 From 83cb4c11d740a3645a5b9a5dafbc13b245c89a07 Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Fri, 7 Jul 2023 08:16:03 -0400 Subject: Change tabs to spaces --- .../org/traccar/protocol/LaipacProtocolDecoder.java | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index dbac159b3..2237dcebc 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -111,23 +111,23 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private String decodeEvent(String event, Position position) { if (event.length() == 1) { - char inputStatus = event.charAt(0); - if (inputStatus >= 'A' && inputStatus <= 'D') { - int inputStatusInt = inputStatus - 'A'; - position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); - position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + char inputStatus = event.charAt(0); + if (inputStatus >= 'A' && inputStatus <= 'D') { + int inputStatusInt = inputStatus - 'A'; + position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); + position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); position.set(Position.PREFIX_IN + 3, 0); - return null; - } else if (inputStatus >= 'O' && inputStatus <= 'R') { + return null; + } else if (inputStatus >= 'O' && inputStatus <= 'R') { int inputStatusInt = inputStatus - 'O'; position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); - position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); position.set(Position.PREFIX_IN + 3, 1); return null; } - } + } - return event; + return event; } -- cgit v1.2.3 From eb7c310a6337328f73c33cb8f0e222dc286925f1 Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Fri, 7 Jul 2023 08:21:01 -0400 Subject: Remove trailing spaces --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 2237dcebc..60a9365c5 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -126,9 +126,9 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return null; } } - + return event; - + } private void sendEventResponse( -- cgit v1.2.3 From 19e00af6d0c7b666841b181438e401bb8e7415ff Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:24:23 -0400 Subject: Use BitUtil instead of logical bitwise AND operator --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 60a9365c5..c2146c22d 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -28,6 +28,7 @@ import org.traccar.helper.PatternBuilder; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; +import org.traccar.helper.BitUtil; import java.net.SocketAddress; import java.util.regex.Pattern; @@ -114,14 +115,14 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { char inputStatus = event.charAt(0); if (inputStatus >= 'A' && inputStatus <= 'D') { int inputStatusInt = inputStatus - 'A'; - position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); - position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + position.set(Position.PREFIX_IN + 1, BitUtil.check(inputStatusInt, 0)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(inputStatusInt, 1)); position.set(Position.PREFIX_IN + 3, 0); return null; } else if (inputStatus >= 'O' && inputStatus <= 'R') { int inputStatusInt = inputStatus - 'O'; - position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); - position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + position.set(Position.PREFIX_IN + 1, BitUtil.check(inputStatusInt, 0)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(inputStatusInt, 1)); position.set(Position.PREFIX_IN + 3, 1); return null; } -- cgit v1.2.3 From 3ca63fb7a345a7b28f58b08874f02659d47d4a66 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 8 Jul 2023 07:25:22 -0700 Subject: Configurable T622 Iridium format --- .../protocol/T622IridiumProtocolDecoder.java | 111 ++++++++++++++++----- .../protocol/T622IridiumProtocolDecoderTest.java | 2 + 2 files changed, 88 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java index 6a81a452a..1178b9b83 100644 --- a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java @@ -19,20 +19,44 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.Protocol; +import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; import org.traccar.session.DeviceSession; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; public class T622IridiumProtocolDecoder extends BaseProtocolDecoder { + private String format; + public T622IridiumProtocolDecoder(Protocol protocol) { super(protocol); } + @Override + protected void init() { + super.init(); + } + + public List getParameters(long deviceId) { + String value = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), deviceId); + return Arrays.stream((value != null ? value : format).split(",")) + .map(s -> Integer.parseInt(s, 16)) + .collect(Collectors.toList()); + } + + public void setFormat(String format) { + this.format = format; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -61,31 +85,68 @@ public class T622IridiumProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - position.setLatitude(buf.readIntLE() / 1000000.0); - position.setLongitude(buf.readIntLE() / 1000000.0); - position.setTime(new Date((buf.readUnsignedIntLE() + 946713600) * 1000)); - position.setValid(buf.readUnsignedByte() > 0); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); - position.setCourse(buf.readUnsignedShortLE()); - - position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); - - position.setAltitude(buf.readShortLE()); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); - position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); - position.set(Position.KEY_INPUT, buf.readUnsignedByte()); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); - - buf.readUnsignedByte(); // geofence + List parameters = getParameters(deviceSession.getDeviceId()); + + for (int parameter : parameters) { + switch (parameter) { + case 0x01: + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + break; + case 0x02: + position.setLatitude(buf.readIntLE() / 1000000.0); + break; + case 0x03: + position.setLongitude(buf.readIntLE() / 1000000.0); + break; + case 0x04: + position.setTime(new Date((buf.readUnsignedIntLE() + 946713600) * 1000)); + break; + case 0x05: + position.setValid(buf.readUnsignedByte() > 0); + break; + case 0x06: + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case 0x07: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + case 0x08: + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + break; + case 0x09: + position.setCourse(buf.readUnsignedShortLE()); + break; + case 0x0A: + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + break; + case 0x0B: + position.setAltitude(buf.readShortLE()); + break; + case 0x0C: + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + break; + case 0x0D: + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); + break; + case 0x14: + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + break; + case 0x15: + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + break; + case 0x19: + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + break; + case 0x1A: + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); + break; + case 0x1B: + buf.readUnsignedByte(); // geofence + break; + default: + break; + } + } return position; } diff --git a/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java index 4bc79fbe8..17b252618 100644 --- a/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java @@ -12,6 +12,8 @@ public class T622IridiumProtocolDecoderTest extends ProtocolTest { var decoder = inject(new T622IridiumProtocolDecoder(null)); + decoder.setFormat("01,02,03,04,05,08"); + verifyPosition(decoder, binary( "01003301001c2a8cef8333303034333430363735343836353000001700006461d512020011232f03a0fff1c85d0612b3f02b00000048")); -- cgit v1.2.3 From 7a59e7a1924bcab3184d1031273c51c9211a842a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 8 Jul 2023 07:28:37 -0700 Subject: Remove init --- src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java index 1178b9b83..27b7baf54 100644 --- a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java @@ -40,11 +40,6 @@ public class T622IridiumProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - @Override - protected void init() { - super.init(); - } - public List getParameters(long deviceId) { String value = AttributeUtil.lookup( getCacheManager(), Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), deviceId); -- cgit v1.2.3 From 5b5f5d04863d3ca766c66441d8e1a8925e3e3d41 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 8 Jul 2023 07:36:01 -0700 Subject: Fix format config --- src/main/java/org/traccar/config/Keys.java | 2 +- src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index e171511e6..6f5360c22 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -238,7 +238,7 @@ public final class Keys { */ public static final ConfigSuffix PROTOCOL_FORMAT = new StringConfigSuffix( ".format", - List.of(KeyType.DEVICE)); + List.of(KeyType.CONFIG, KeyType.DEVICE)); /** * Protocol date format. Used by protocols that have configurable date format. diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java index aa23bfac5..193005e28 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -61,10 +61,10 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { @Override protected void init() { setFormat(getConfig().getString( - getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," + Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," + "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#")); - setDateFormat(getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss")); + setDateFormat(getConfig().getString(Keys.PROTOCOL_DATE_FORMAT.withPrefix(getProtocolName()), "yyMMddHHmmss")); } public String[] getFormat(long deviceId) { -- cgit v1.2.3 From 8790fed8864f9ce41fe219f8a757cc9dedec272d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 9 Jul 2023 06:32:18 -0700 Subject: Check enabled notification types --- src/main/java/org/traccar/notification/NotificatorManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java index c3ee7b480..b6ee760f3 100644 --- a/src/main/java/org/traccar/notification/NotificatorManager.java +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -66,7 +66,7 @@ public class NotificatorManager { public Notificator getNotificator(String type) { var clazz = NOTIFICATORS_ALL.get(type); - if (clazz != null) { + if (clazz != null && types.contains(type)) { var notificator = injector.getInstance(clazz); if (notificator != null) { return notificator; -- cgit v1.2.3 From 92e90931cd806d4b2f53ff946a19b46595f856e9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 9 Jul 2023 06:37:34 -0700 Subject: Support new line in text commands --- src/main/java/org/traccar/BaseProtocol.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index d19fc307e..1948becc0 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -105,7 +105,8 @@ public abstract class BaseProtocol implements Protocol { } else if (command.getType().equals(Command.TYPE_CUSTOM)) { String data = command.getString(Command.KEY_DATA); if (BasePipelineFactory.getHandler(channel.pipeline(), StringEncoder.class) != null) { - channel.writeAndFlush(new NetworkMessage(data, remoteAddress)); + channel.writeAndFlush(new NetworkMessage( + data.replace("\\r", "\r").replace("\\n", "\n"), remoteAddress)); } else { ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(data)); channel.writeAndFlush(new NetworkMessage(buf, remoteAddress)); -- cgit v1.2.3 From d2ce5af3478265c6c047f5ec4bf206baebb467d1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 9 Jul 2023 07:32:49 -0700 Subject: Handle R31 protocol variant --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 6 +++++- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 38c2219f8..5db06fc41 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -806,7 +806,11 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } if (hasLbs(type) && buf.readableBytes() > 6) { - decodeLbs(position, buf, type, hasStatus(type) && type != MSG_LBS_ALARM && type != MSG_LBS_STATUS); + boolean hasLength = hasStatus(type) + && type != MSG_LBS_STATUS + && type != MSG_LBS_ALARM + && (type != MSG_GPS_LBS_STATUS_1 || variant != Variant.VXT01); + decodeLbs(position, buf, type, hasLength); } if (hasStatus(type)) { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 937c7eca1..04f41a5ee 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78782416160501000221c0027c5e180c2b9c8d00150301cc002503002bde20050f01000004bd320d0a"), + Position.KEY_ALARM, Position.ALARM_SOS); + verifyAttribute(decoder, binary( "78780a130604ea04000006bc8a0d0a"), Position.KEY_POWER, 0.0); -- cgit v1.2.3 From 536888fd7e64f00ca9693ea9b41624360949c8ab Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Sun, 9 Jul 2023 14:01:12 -0400 Subject: Conditionally set digital input 3 and analog input 2 according to device model --- .../traccar/protocol/LaipacProtocolDecoder.java | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index c2146c22d..df0f1e2ed 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -113,17 +113,22 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { if (event.length() == 1) { char inputStatus = event.charAt(0); + String deviceModel = device.getModel(); if (inputStatus >= 'A' && inputStatus <= 'D') { int inputStatusInt = inputStatus - 'A'; - position.set(Position.PREFIX_IN + 1, BitUtil.check(inputStatusInt, 0)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(inputStatusInt, 1)); - position.set(Position.PREFIX_IN + 3, 0); + position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); + position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); + if (deviceModel == "SF-Lite") { + position.set(Position.PREFIX_IN + 3, false); + } return null; } else if (inputStatus >= 'O' && inputStatus <= 'R') { int inputStatusInt = inputStatus - 'O'; - position.set(Position.PREFIX_IN + 1, BitUtil.check(inputStatusInt, 0)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(inputStatusInt, 1)); - position.set(Position.PREFIX_IN + 3, 1); + position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); + position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); + if (deviceModel == "SF-Lite") { + position.set(Position.PREFIX_IN + 3, true); + } return null; } } @@ -247,7 +252,11 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); position.set(Position.KEY_GPS, parser.nextInt()); position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); + + String deviceModel = device.getModel(); + if (deviceModel == "AVL110" || deviceModel == "AVL120") { + position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); + } Integer lac = parser.nextHexInt(); Integer cid = parser.nextHexInt(); -- cgit v1.2.3 From 67f05acaa4e72db3576418a150ebbe53971309bf Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Sun, 9 Jul 2023 14:34:32 -0400 Subject: Fix some errors --- .../traccar/protocol/LaipacProtocolDecoder.java | 29 +++++++++++++--------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index df0f1e2ed..5218cfc16 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -109,16 +109,15 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { } } - private String decodeEvent(String event, Position position) { + private String decodeEvent(String event, Position position, String deviceModel) { if (event.length() == 1) { char inputStatus = event.charAt(0); - String deviceModel = device.getModel(); if (inputStatus >= 'A' && inputStatus <= 'D') { int inputStatusInt = inputStatus - 'A'; position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); - if (deviceModel == "SF-Lite") { + if ("SF-Lite".equals(deviceModel)) { position.set(Position.PREFIX_IN + 3, false); } return null; @@ -126,7 +125,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { int inputStatusInt = inputStatus - 'O'; position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); - if (deviceModel == "SF-Lite") { + if ("SF-Lite".equals(deviceModel)) { position.set(Position.PREFIX_IN + 3, true); } return null; @@ -220,15 +219,22 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return null; } + String deviceId = parser.next(); + DeviceSession deviceSession = - getDeviceSession(channel, remoteAddress, parser.next()); + getDeviceSession(channel, remoteAddress, deviceId); if (deviceSession == null) { return null; } - Position position = new Position(getProtocolName()); + String deviceModel = null; + Device device = getCacheManager().getObject(Device.class, deviceId); + if (device != null) { + deviceModel = device.getModel(); + } - position.setDeviceId(deviceSession.getDeviceId()); + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceId); DateBuilder dateBuilder = new DateBuilder() .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); @@ -247,14 +253,13 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String event = parser.next(); position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.set(Position.KEY_EVENT, decodeEvent(event, position)); + position.set(Position.KEY_EVENT, decodeEvent(event, position, deviceModel)); position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); position.set(Position.KEY_GPS, parser.nextInt()); position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); - - String deviceModel = device.getModel(); - if (deviceModel == "AVL110" || deviceModel == "AVL120") { + + if ("AVL110".equals(deviceModel) || "AVL120".equals(deviceModel)) { position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); } @@ -275,7 +280,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { sendAcknowledge(status, event, checksum, channel, remoteAddress); String devicePassword = AttributeUtil.getDevicePassword( - getCacheManager(), deviceSession.getDeviceId(), getProtocolName(), DEFAULT_DEVICE_PASSWORD); + getCacheManager(), deviceId, getProtocolName(), DEFAULT_DEVICE_PASSWORD); sendEventResponse(event, devicePassword, channel, remoteAddress); } -- cgit v1.2.3 From e63b6bd4868f367c581db40997f741d00587b3b2 Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Sun, 9 Jul 2023 14:37:30 -0400 Subject: Fix more errors --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 5218cfc16..e3409c85a 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -28,6 +28,7 @@ import org.traccar.helper.PatternBuilder; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; +import org.traccar.model.Device; import org.traccar.helper.BitUtil; import java.net.SocketAddress; -- cgit v1.2.3 From 7ade92a97f41951aecfbb9de720780cf5232e2c1 Mon Sep 17 00:00:00 2001 From: edvalley <52469633+edvalley@users.noreply.github.com> Date: Sun, 9 Jul 2023 16:06:18 -0400 Subject: Fix more errors --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index e3409c85a..f0753cb5c 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -220,22 +220,21 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return null; } - String deviceId = parser.next(); - DeviceSession deviceSession = - getDeviceSession(channel, remoteAddress, deviceId); + getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { return null; } String deviceModel = null; - Device device = getCacheManager().getObject(Device.class, deviceId); + Device device = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()); if (device != null) { deviceModel = device.getModel(); } Position position = new Position(getProtocolName()); - position.setDeviceId(deviceId); + + position.setDeviceId(deviceSession.getDeviceId()); DateBuilder dateBuilder = new DateBuilder() .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); @@ -281,7 +280,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { sendAcknowledge(status, event, checksum, channel, remoteAddress); String devicePassword = AttributeUtil.getDevicePassword( - getCacheManager(), deviceId, getProtocolName(), DEFAULT_DEVICE_PASSWORD); + getCacheManager(), deviceSession.getDeviceId(), getProtocolName(), DEFAULT_DEVICE_PASSWORD); sendEventResponse(event, devicePassword, channel, remoteAddress); } -- cgit v1.2.3 From 779486a30483f7ab9c2c0f4c39c6a4e14319b330 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Sun, 9 Jul 2023 17:07:35 -0400 Subject: Fix more errors --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index f0753cb5c..de039a2fd 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -231,6 +231,9 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { if (device != null) { deviceModel = device.getModel(); } + if (deviceModel == null) { + deviceModel = ""; + } Position position = new Position(getProtocolName()); @@ -261,6 +264,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { if ("AVL110".equals(deviceModel) || "AVL120".equals(deviceModel)) { position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); + } else { + parser.next(); } Integer lac = parser.nextHexInt(); -- cgit v1.2.3 From 97240fd579c2d01f43a5b7ba1f9b16bad19085f2 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Sun, 9 Jul 2023 17:11:55 -0400 Subject: Remove unneded code --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index de039a2fd..6a5b67669 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -231,9 +231,6 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { if (device != null) { deviceModel = device.getModel(); } - if (deviceModel == null) { - deviceModel = ""; - } Position position = new Position(getProtocolName()); -- cgit v1.2.3 From 60522a68d292541c44efa3736967f471d4347a50 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Sun, 9 Jul 2023 18:04:33 -0400 Subject: Follow refactor suggestion --- .../java/org/traccar/protocol/LaipacProtocolDecoder.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 6a5b67669..5745909c7 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -110,7 +110,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { } } - private String decodeEvent(String event, Position position, String deviceModel) { + private String decodeEvent(String event, Position position, String model) { if (event.length() == 1) { char inputStatus = event.charAt(0); @@ -118,7 +118,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { int inputStatusInt = inputStatus - 'A'; position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); - if ("SF-Lite".equals(deviceModel)) { + if ("SF-Lite".equals(model)) { position.set(Position.PREFIX_IN + 3, false); } return null; @@ -126,7 +126,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { int inputStatusInt = inputStatus - 'O'; position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); - if ("SF-Lite".equals(deviceModel)) { + if ("SF-Lite".equals(model)) { position.set(Position.PREFIX_IN + 3, true); } return null; @@ -226,11 +226,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return null; } - String deviceModel = null; - Device device = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()); - if (device != null) { - deviceModel = device.getModel(); - } + String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); Position position = new Position(getProtocolName()); @@ -253,13 +249,13 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String event = parser.next(); position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.set(Position.KEY_EVENT, decodeEvent(event, position, deviceModel)); + position.set(Position.KEY_EVENT, decodeEvent(event, position, model)); position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); position.set(Position.KEY_GPS, parser.nextInt()); position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); - if ("AVL110".equals(deviceModel) || "AVL120".equals(deviceModel)) { + if ("AVL110".equals(model) || "AVL120".equals(model)) { position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); } else { parser.next(); -- cgit v1.2.3 From b5d5ec43181a428741c312462024d17ff7fbc676 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 11 Jul 2023 06:27:03 -0700 Subject: Fix services decoding --- .../java/org/traccar/protocol/Minifinder2ProtocolDecoder.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index cd8d8e0cf..85589b064 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -148,7 +148,7 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { int type = buf.readUnsignedByte(); if (BitUtil.check(flags, 4)) { - sendResponse(channel, remoteAddress, index, type, buf); + sendResponse(channel, remoteAddress, index, type, buf.slice()); } if (type == MSG_DATA || type == MSG_SERVICES) { @@ -179,8 +179,9 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { case 0x01: deviceSession = getDeviceSession( channel, remoteAddress, buf.readCharSequence(15, StandardCharsets.US_ASCII).toString()); - - position.setDeviceId(deviceSession.getDeviceId()); + if (deviceSession == null) { + return null; + } break; case 0x02: long alarm = buf.readUnsignedIntLE(); -- cgit v1.2.3 From b3c6e22fc19ceeceb0f318131538b5e1d260450c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 12 Jul 2023 06:24:15 -0700 Subject: Ignore R31 alarm extension --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 5 ++++- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 5db06fc41..383d4cb3a 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -828,7 +828,10 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } else { position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 100 / 6); position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + short alarmExtension = buf.readUnsignedByte(); + if (variant != Variant.VXT01) { + position.set(Position.KEY_ALARM, decodeAlarm(alarmExtension)); + } } } diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 04f41a5ee..fac92d70f 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -18,7 +18,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { "78780D01086471700328358100093F040D0A")); verifyAttribute(decoder, binary( - "78782416160501000221c0027c5e180c2b9c8d00150301cc002503002bde20050f01000004bd320d0a"), + "7878241617070a150e24ca01fba0040780e177005c0001720253360027db6204e40400004bf1e90d0a"), Position.KEY_ALARM, Position.ALARM_SOS); verifyAttribute(decoder, binary( -- cgit v1.2.3 From 7325030436e5fc42b6998240a0c5696a1d4fed5a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 12 Jul 2023 07:27:40 -0700 Subject: Fix GT06 transparent data --- src/main/java/org/traccar/helper/BufferUtil.java | 12 ++++++++++++ .../java/org/traccar/protocol/Gt06ProtocolDecoder.java | 17 ++++++----------- .../org/traccar/protocol/TeltonikaProtocolDecoder.java | 17 +++-------------- .../org/traccar/protocol/Gt06ProtocolDecoderTest.java | 13 +++++++++---- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java index d1025f548..12c31ba9d 100644 --- a/src/main/java/org/traccar/helper/BufferUtil.java +++ b/src/main/java/org/traccar/helper/BufferUtil.java @@ -71,4 +71,16 @@ public final class BufferUtil { } } + public static boolean isPrintable(ByteBuf buf, int length) { + boolean printable = true; + for (int i = 0; i < length; i++) { + byte b = buf.getByte(buf.readerIndex() + i); + if (b < 32 && b != '\r' && b != '\n') { + printable = false; + break; + } + } + return printable; + } + } diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 383d4cb3a..e1bc2b5ad 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -1382,19 +1383,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); buf.readUnsignedByte(); // external device type code - int length = buf.readableBytes() - 9; // line break + checksum + index + checksum + footer - if (length <= 0) { - return null; - } else if (length < 8) { - position.set( - Position.PREFIX_TEMP + 1, - Double.parseDouble(buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString())); + ByteBuf data = buf.readSlice(buf.readableBytes() - 6); // index + checksum + footer + if (BufferUtil.isPrintable(data, data.readableBytes())) { + String value = data.readCharSequence(data.readableBytes(), StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_RESULT, value.trim()); } else { - buf.readUnsignedByte(); // card type - position.set( - Position.KEY_DRIVER_UNIQUE_ID, - buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString()); + position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(data)); } return position; diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index c8e0005f9..e888642b4 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.model.Device; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; @@ -112,18 +113,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } } - private boolean isPrintable(ByteBuf buf, int length) { - boolean printable = true; - for (int i = 0; i < length; i++) { - byte b = buf.getByte(buf.readerIndex() + i); - if (b < 32 && b != '\r' && b != '\n') { - printable = false; - break; - } - } - return printable; - } - private void decodeSerial( Channel channel, SocketAddress remoteAddress, DeviceSession deviceSession, Position position, ByteBuf buf) { @@ -169,7 +158,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_TYPE, type); int length = buf.readInt(); - if (isPrintable(buf, length)) { + if (BufferUtil.isPrintable(buf, length)) { String data = buf.readSlice(length).toString(StandardCharsets.US_ASCII).trim(); if (data.startsWith("UUUUww") && data.endsWith("SSS")) { String[] values = data.substring(6, data.length() - 4).split(";"); @@ -636,7 +625,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // type int length = buf.readInt() - 4; getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); - if (isPrintable(buf, length)) { + if (BufferUtil.isPrintable(buf, length)) { String data = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim(); if (data.startsWith("GTSL")) { position.set(Position.KEY_DRIVER_UNIQUE_ID, data.split("\\|")[4]); diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index fac92d70f..26f300554 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + /*verifyAttribute(decoder, binary( + "797900109b0344373532304136320d0a000f87f00d0a"), + Position.KEY_DRIVER_UNIQUE_ID, "44373532304136320d0a");*/ + verifyAttribute(decoder, binary( "7878241617070a150e24ca01fba0040780e177005c0001720253360027db6204e40400004bf1e90d0a"), Position.KEY_ALARM, Position.ALARM_SOS); @@ -111,8 +115,9 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { "7878281520000000003c49434349443a38393838323339303030303039373330323635303e00020d446f260d0a"), Position.KEY_ICCID, "89882390000097302650"); - verifyNull(decoder, binary( - "797900099b0380d600046f91e90d0a")); + verifyAttribute(decoder, binary( + "797900099b0380d600046f91e90d0a"), + Position.KEY_RESULT, "80d600"); verifyNull(decoder, binary( "797900a56615010d081f3b012c323131303d30303033643238342c323130353d30303030316332302c323130623d30303030326537632c323130633d30303033643238342c323130663d30303030306331632c323130643d30303030323166632c323161363d30303030303030302c323130343d30303030306531302c323132663d30303030303030302c323134353d30303030303030302ccb03851f5f03c020525514a7003e216a0d0a")); @@ -125,7 +130,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyAttribute(decoder, binary( "7979000E9B0332382E33A1E60D0A0289BE490D0A"), - Position.PREFIX_TEMP + 1, 28.3); + Position.KEY_RESULT, "32382e33a1e60d0a"); verifyPosition(decoder, binary( "7878353714080d05000ac500a886eb0b7522f000100001fe0a05ea004f1b000001002e0400002328003b0217c0003c0401020001002c468a0d0a")); @@ -168,7 +173,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyAttribute(decoder, binary( "797900149b03023539303042343843454238410300139ba40d0a"), - Position.KEY_DRIVER_UNIQUE_ID, "5900B48CEB"); + Position.KEY_RESULT, "0235393030423438434542384103"); verifyPosition(decoder, binary( "787821121303120b2524c70138e363085b549003d43301940057d200cd52c000006aa1ca0d0a")); -- cgit v1.2.3 From 2be2a4558ace9825a69aecf6329305490eb5fe5e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 12 Jul 2023 07:44:58 -0700 Subject: Support JM-VL03 messages --- .../java/org/traccar/protocol/Gt06ProtocolDecoder.java | 14 ++++++++++---- .../java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 7 +++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index e1bc2b5ad..f7cdd3920 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -96,7 +96,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_INFO = 0x94; public static final int MSG_SERIAL = 0x9B; public static final int MSG_STRING_INFO = 0x21; - public static final int MSG_GPS_2 = 0xA0; // GK310 + public static final int MSG_GPS_LBS_7 = 0xA0; // GK310 & JM-VL03 public static final int MSG_LBS_2 = 0xA1; // GK310 public static final int MSG_WIFI_3 = 0xA2; // GK310 public static final int MSG_FENCE_SINGLE = 0xA3; // GK310 @@ -170,7 +170,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { case MSG_GPS_LBS_STATUS_4: case MSG_GPS_PHONE: case MSG_GPS_LBS_EXTEND: - case MSG_GPS_2: + case MSG_GPS_LBS_7: case MSG_FENCE_SINGLE: case MSG_FENCE_MULTI: return true; @@ -192,7 +192,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { case MSG_GPS_LBS_STATUS_2: case MSG_GPS_LBS_STATUS_3: case MSG_GPS_LBS_STATUS_4: - case MSG_GPS_2: + case MSG_GPS_LBS_7: case MSG_FENCE_SINGLE: case MSG_FENCE_MULTI: case MSG_LBS_ALARM: @@ -351,7 +351,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { lac = buf.readUnsignedShort(); } long cid; - if (type == MSG_LBS_ALARM) { + if (type == MSG_LBS_ALARM || type == MSG_GPS_LBS_7) { cid = buf.readLong(); } else if (type == MSG_GPS_LBS_6) { cid = buf.readUnsignedInt(); @@ -919,6 +919,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } } + if (type == MSG_GPS_LBS_7) { + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + buf.readUnsignedByte(); // upload mode + position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0 ? true : null); + } + if (buf.readableBytes() == 4 + 6) { position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); } diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 26f300554..cc71eb9bd 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,9 +17,12 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); - /*verifyAttribute(decoder, binary( + verifyNotNull(decoder, binary( + "787829a0170704112226cf0163fe7c0420f6f000091302d402000091290000000007186b8f01030001460d010d0a")); + + verifyAttribute(decoder, binary( "797900109b0344373532304136320d0a000f87f00d0a"), - Position.KEY_DRIVER_UNIQUE_ID, "44373532304136320d0a");*/ + Position.KEY_RESULT, "D7520A62"); verifyAttribute(decoder, binary( "7878241617070a150e24ca01fba0040780e177005c0001720253360027db6204e40400004bf1e90d0a"), -- cgit v1.2.3 From 105873ab5256a774ef07ca7ee459da0917829591 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 13 Jul 2023 07:00:45 -0700 Subject: Add Eview Pet result support --- .../traccar/protocol/Minifinder2ProtocolDecoder.java | 17 +++++++++++++++++ .../protocol/Minifinder2ProtocolDecoderTest.java | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 85589b064..6289bd2eb 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -324,6 +324,23 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { return positions; + } else if (type == MSG_RESPONSE) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + buf.readUnsignedByte(); // length + position.set(Position.KEY_RESULT, String.valueOf(buf.readUnsignedByte())); + + return position; + } return null; diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java index 587a520d1..64d245a8e 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class Minifinder2ProtocolDecoderTest extends ProtocolTest { @@ -14,6 +15,10 @@ public class Minifinder2ProtocolDecoderTest extends ProtocolTest { "ab101c00d6f61e000110013836333932313033393939363038300937efd201640c000000"), "barkCount", 12L); + verifyAttribute(decoder, binary( + "ab00030008c700007f0100"), + Position.KEY_RESULT, "0"); + verifyAttribute(decoder, binary( "ab102600080f1400011001383633393231303339393833343736092429b347633003a96409020000008027b34763"), "bark", true); -- cgit v1.2.3 From bd64dc0bc759e8325f09686909c25f3a08fbf686 Mon Sep 17 00:00:00 2001 From: Rodolfo Silva Date: Thu, 13 Jul 2023 14:26:34 -0300 Subject: AMQP Forwarder Add support to forward events and positions to AMQP (RabbitMQ). --- build.gradle | 1 + src/main/java/org/traccar/MainModule.java | 6 ++ src/main/java/org/traccar/config/Keys.java | 20 +++++- .../org/traccar/forward/EventForwarderAmqp.java | 81 ++++++++++++++++++++++ .../org/traccar/forward/PositionForwarderAmqp.java | 80 +++++++++++++++++++++ 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/traccar/forward/EventForwarderAmqp.java create mode 100644 src/main/java/org/traccar/forward/PositionForwarderAmqp.java diff --git a/build.gradle b/build.gradle index b4e11ed98..d08dfebc5 100644 --- a/build.gradle +++ b/build.gradle @@ -89,6 +89,7 @@ dependencies { implementation "redis.clients:jedis:4.4.1" implementation "com.google.firebase:firebase-admin:9.1.1" implementation "com.nimbusds:oauth2-oidc-sdk:10.9.1" + implementation "com.rabbitmq:amqp-client:5.18.0" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testImplementation "org.mockito:mockito-core:5.3.1" diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index b7bdbc6bf..f5db75846 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -37,10 +37,12 @@ import org.traccar.database.OpenIdProvider; import org.traccar.database.StatisticsManager; import org.traccar.forward.EventForwarder; import org.traccar.forward.EventForwarderJson; +import org.traccar.forward.EventForwarderAmqp; import org.traccar.forward.EventForwarderKafka; import org.traccar.forward.EventForwarderMqtt; import org.traccar.forward.PositionForwarder; import org.traccar.forward.PositionForwarderJson; +import org.traccar.forward.PositionForwarderAmqp; import org.traccar.forward.PositionForwarderKafka; import org.traccar.forward.PositionForwarderRedis; import org.traccar.forward.PositionForwarderUrl; @@ -360,6 +362,8 @@ public class MainModule extends AbstractModule { if (config.hasKey(Keys.EVENT_FORWARD_URL)) { String forwardType = config.getString(Keys.EVENT_FORWARD_TYPE); switch (forwardType) { + case "amqp": + return new EventForwarderAmqp(config, objectMapper); case "kafka": return new EventForwarderKafka(config, objectMapper); case "mqtt": @@ -379,6 +383,8 @@ public class MainModule extends AbstractModule { switch (config.getString(Keys.FORWARD_TYPE)) { case "json": return new PositionForwarderJson(config, client, objectMapper); + case "amqp": + return new PositionForwarderAmqp(config, objectMapper); case "kafka": return new PositionForwarderKafka(config, objectMapper); case "redis": diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6f5360c22..314ac0df2 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -837,7 +837,15 @@ public final class Keys { "url"); /** - * Position forwarding Kafka topic. + * Position forwarding AMQP exchange. + */ + public static final ConfigKey FORWARD_EXCHANGE = new StringConfigKey( + "forward.exchange", + List.of(KeyType.CONFIG), + "traccar"); + + /** + * Position forwarding Kafka topic or AQMP Routing Key. */ public static final ConfigKey FORWARD_TOPIC = new StringConfigKey( "forward.topic", @@ -906,7 +914,15 @@ public final class Keys { "json"); /** - * Events forwarding Kafka topic. + * Events forwarding AMQP exchange. + */ + public static final ConfigKey EVENT_FORWARD_EXCHANGE = new StringConfigKey( + "event.forward.exchange", + List.of(KeyType.CONFIG), + "traccar"); + + /** + * Events forwarding Kafka topic or AQMP Routing Key. */ public static final ConfigKey EVENT_FORWARD_TOPIC = new StringConfigKey( "event.forward.topic", diff --git a/src/main/java/org/traccar/forward/EventForwarderAmqp.java b/src/main/java/org/traccar/forward/EventForwarderAmqp.java new file mode 100644 index 000000000..64edbe8a5 --- /dev/null +++ b/src/main/java/org/traccar/forward/EventForwarderAmqp.java @@ -0,0 +1,81 @@ +/* + * Copyright 2022 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.forward; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.Properties; +import java.util.concurrent.TimeoutException; + +public class EventForwarderAmqp implements EventForwarder { + + private final Channel channel; + private final ObjectMapper objectMapper; + + private final String exchange; + private final String topic; + + public EventForwarderAmqp(Config config, ObjectMapper objectMapper) { + ConnectionFactory factory = new ConnectionFactory(); + try { + factory.setUri(config.getString(Keys.EVENT_FORWARD_URL)); + } catch (NoSuchAlgorithmException | URISyntaxException | KeyManagementException e) { + throw new RuntimeException(e); + } + + try { + Connection connection = factory.newConnection(); + exchange = config.getString(Keys.EVENT_FORWARD_EXCHANGE); + topic = config.getString(Keys.EVENT_FORWARD_TOPIC); + channel = connection.createChannel(); + channel.exchangeDeclare(exchange, "topic", true); + this.objectMapper = objectMapper; + } catch (IOException | TimeoutException e) { + throw new RuntimeException(e); + } + } + + @Override + public void forward(EventData eventData, ResultHandler resultHandler) { + try { + String value = objectMapper.writeValueAsString(eventData); + + BasicProperties properties = new BasicProperties.Builder() + .contentType("application/json") + .contentEncoding("string") + .deliveryMode(2) + .priority(10) + .build(); + + channel.basicPublish(exchange, topic, properties, value.getBytes()); + resultHandler.onResult(true, null); + } catch (IOException e) { + resultHandler.onResult(false, e); + } + } +} diff --git a/src/main/java/org/traccar/forward/PositionForwarderAmqp.java b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java new file mode 100644 index 000000000..c55ca3d73 --- /dev/null +++ b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java @@ -0,0 +1,80 @@ +/* + * Copyright 2022 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.forward; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.Properties; +import java.util.concurrent.TimeoutException; + +public class PositionForwarderAmqp implements PositionForwarder { + + private final Channel channel; + private final ObjectMapper objectMapper; + + private final String exchange; + private final String topic; + + public PositionForwarderAmqp(Config config, ObjectMapper objectMapper) { + ConnectionFactory factory = new ConnectionFactory(); + try { + factory.setUri(config.getString(Keys.FORWARD_URL)); + } catch (NoSuchAlgorithmException | URISyntaxException | KeyManagementException e) { + throw new RuntimeException(e); + } + + try { + Connection connection = factory.newConnection(); + topic = config.getString(Keys.FORWARD_TOPIC); + exchange = config.getString(Keys.EVENT_FORWARD_EXCHANGE); + channel = connection.createChannel(); + channel.exchangeDeclare(exchange, "topic", true); + this.objectMapper = objectMapper; + } catch (IOException | TimeoutException e) { + throw new RuntimeException(e); + } + } + + @Override + public void forward(PositionData positionData, ResultHandler resultHandler) { + try { + String value = objectMapper.writeValueAsString(positionData); + + BasicProperties properties = new BasicProperties.Builder() + .contentType("application/json") + .contentEncoding("string") + .deliveryMode(2) + .priority(10) + .build(); + + channel.basicPublish(exchange, topic, properties, value.getBytes()); + resultHandler.onResult(true, null); + } catch (IOException e) { + resultHandler.onResult(false, e); + } + } +} -- cgit v1.2.3 From 104e8a4a7829b4b4a4723a715cc2b15899fa8b9f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 14 Jul 2023 06:49:08 -0700 Subject: Option to disable Topic commands --- src/main/java/org/traccar/config/Keys.java | 7 +++++++ src/main/java/org/traccar/protocol/TopinProtocol.java | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6f5360c22..7ad981799 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -233,6 +233,13 @@ public final class Keys { ".includeTemp", List.of(KeyType.CONFIG, KeyType.DEVICE)); + /** + * Disable commands for the protocol. Not all protocols support this option. + */ + public static final ConfigSuffix PROTOCOL_DISABLE_COMMANDS = new BooleanConfigSuffix( + ".disableCommands", + List.of(KeyType.CONFIG)); + /** * Protocol format. Used by protocols that have configurable message format. */ diff --git a/src/main/java/org/traccar/protocol/TopinProtocol.java b/src/main/java/org/traccar/protocol/TopinProtocol.java index b15373d71..37afac582 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocol.java +++ b/src/main/java/org/traccar/protocol/TopinProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -19,6 +19,7 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.model.Command; import javax.inject.Inject; @@ -27,8 +28,10 @@ public class TopinProtocol extends BaseProtocol { @Inject public TopinProtocol(Config config) { - setSupportedDataCommands( - Command.TYPE_SOS_NUMBER); + if (!config.getBoolean(Keys.PROTOCOL_DISABLE_COMMANDS.withPrefix(getName()))) { + setSupportedDataCommands( + Command.TYPE_SOS_NUMBER); + } addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { -- cgit v1.2.3 From 007b4007e063cfb966a4024ef267992a4f1f9ccb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 14 Jul 2023 07:41:31 -0700 Subject: Trackology Tracker Type-A protocol --- src/main/java/org/traccar/protocol/TopinProtocolDecoder.java | 7 ++++++- src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java index a1d5481db..b5dd3c4b9 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java @@ -48,7 +48,11 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_GPS = 0x10; public static final int MSG_GPS_OFFLINE = 0x11; public static final int MSG_STATUS = 0x13; + public static final int MSG_SLEEP = 0x14; + public static final int MSG_FACTORY_RESET = 0x15; public static final int MSG_WIFI_OFFLINE = 0x17; + public static final int MSG_LBS_WIFI = 0x18; + public static final int MSG_LBS_WIFI_OFFLINE = 0x19; public static final int MSG_TIME_UPDATE = 0x30; public static final int MSG_SOS_NUMBER = 0x41; public static final int MSG_WIFI = 0x69; @@ -216,7 +220,8 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { return position; - } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE) { + } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE + || type == MSG_LBS_WIFI || type == MSG_LBS_WIFI_OFFLINE) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); diff --git a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java index 763c4f2da..b55e12e9d 100644 --- a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java @@ -17,6 +17,9 @@ public class TopinProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780d0103593390754169634d0d0a")); + verifyNotNull(decoder, binary( + "787803181604130318491475905bd30e25001e10bbf7635d14759006e626560401cc00000028660090df425f000028660090df576c00002866009487566700002866009ca15667000d0a")); + verifyAttribute(decoder, binary( "7878006921120412565802010601071e4a9764071e4a9864010d0a"), Position.KEY_ALARM, Position.ALARM_VIBRATION); -- cgit v1.2.3 From 74d73a9dc28fc608117c04da4652d43f633a72c5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 16 Jul 2023 08:02:56 -0700 Subject: Improve user check --- src/main/java/org/traccar/api/security/PermissionsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index 38bf48f30..7f5a46225 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -181,7 +181,7 @@ public class PermissionsService { || before.getUserLimit() != after.getUserLimit()) { checkAdmin(userId); } - User user = getUser(userId); + User user = userId > 0 ? getUser(userId) : null; if (user != null && user.getExpirationTime() != null && !Objects.equals(before.getExpirationTime(), after.getExpirationTime()) && (after.getExpirationTime() == null -- cgit v1.2.3 From 3642b952086355f5f2a52f7dc9b2cdfea4c02e31 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 17 Jul 2023 21:00:44 -0700 Subject: Handle HS-5000 cell id --- src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 2fb7c6e92..1ad27be5f 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -284,7 +284,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { String[] values = cell.split("@"); network.addCellTower(CellTower.from( Integer.parseInt(values[0]), Integer.parseInt(values[1]), - Integer.parseInt(values[2], 16), Integer.parseInt(values[3], 16))); + Integer.parseInt(values[2], 16), Long.parseLong(values[3], 16))); } break; case 0x0021: diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java index fe4b077c6..a54fa53c6 100644 --- a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java @@ -31,6 +31,9 @@ public class HuaShengProtocolDecoderTest extends ProtocolTest { "c000000049aa0000000000028e8800000032303038323630373534323800e1d47fffcd163d0000000000f30000000100157703f8000046000000000aade0ffffffff0011000800000496c0"), Position.KEY_HOURS, 58.7); + verifyNotNull(decoder, binary( + "c0000000b1aa000000000000050000000031393730303130313134303200000000000000000000000000000000000100180000000000000000000000000000000000c57e000005000a1a000000c569000900155756575a5a5a43445a4e57313139313534000f00133836393733313035313339393231300010000c302e30303030303000110008000000000014000bf800002800000000150006000000200016353035403031403040313337313931363831c0")); + verifyNotNull(decoder, binary( "c000000077aa00000000000070020000003230303132373035313635330000000000000000000000000000000000010015ffffffff000000000000019dffffffffff0005000a1f00000e455a00200019313238354031406666666540386233663930634030000f0013333536373236313038313335343530c0")); -- cgit v1.2.3 From 548b19193febdd7e53e4e42014ad46235866de58 Mon Sep 17 00:00:00 2001 From: Jacob Schooley Date: Tue, 18 Jul 2023 23:45:42 -0400 Subject: Set session cookie max age if web.sessionTimeout is set --- src/main/java/org/traccar/web/WebServer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index b5d2f2771..184c546d5 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -193,14 +193,16 @@ public class WebServer implements LifecycleObject { sessionHandler.setSessionCache(sessionCache); } + SessionCookieConfig sessionCookieConfig = servletHandler.getServletContext().getSessionCookieConfig(); + int sessionTimeout = config.getInteger(Keys.WEB_SESSION_TIMEOUT); if (sessionTimeout > 0) { servletHandler.getSessionHandler().setMaxInactiveInterval(sessionTimeout); + sessionCookieConfig.setMaxAge(sessionTimeout); } String sameSiteCookie = config.getString(Keys.WEB_SAME_SITE_COOKIE); if (sameSiteCookie != null) { - SessionCookieConfig sessionCookieConfig = servletHandler.getServletContext().getSessionCookieConfig(); switch (sameSiteCookie.toLowerCase()) { case "lax": sessionCookieConfig.setComment(HttpCookie.SAME_SITE_LAX_COMMENT); -- cgit v1.2.3 From 5a1a8d9192ee44b116f10e5ce3551a4e4bc70deb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 19 Jul 2023 06:26:19 -0700 Subject: Fix date decoding --- src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java | 2 +- .../java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java index 27b7baf54..9e64ec9be 100644 --- a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java @@ -94,7 +94,7 @@ public class T622IridiumProtocolDecoder extends BaseProtocolDecoder { position.setLongitude(buf.readIntLE() / 1000000.0); break; case 0x04: - position.setTime(new Date((buf.readUnsignedIntLE() + 946713600) * 1000)); + position.setTime(new Date((buf.readUnsignedIntLE() + 946684800) * 1000)); break; case 0x05: position.setValid(buf.readUnsignedByte() > 0); diff --git a/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java index 17b252618..ff5d5b0a0 100644 --- a/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java @@ -1,12 +1,10 @@ package org.traccar.protocol; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class T622IridiumProtocolDecoderTest extends ProtocolTest { - @Disabled @Test public void testDecode() throws Exception { @@ -15,7 +13,8 @@ public class T622IridiumProtocolDecoderTest extends ProtocolTest { decoder.setFormat("01,02,03,04,05,08"); verifyPosition(decoder, binary( - "01003301001c2a8cef8333303034333430363735343836353000001700006461d512020011232f03a0fff1c85d0612b3f02b00000048")); + "01003501001c68b2cb1733303034333430363735343836353000016e000064b5f497020013234c5ea0ff1c365d0600b1482c010000cf0004"), + position("2023-07-18 02:10:08.000", true, -6.26732, 106.77200)); } -- cgit v1.2.3 From dcef13b1fc7cf052463e11532365b3ad1f948b99 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 19 Jul 2023 07:45:13 -0700 Subject: Trim important fields --- src/main/java/org/traccar/model/Device.java | 4 ++-- src/main/java/org/traccar/model/Driver.java | 2 +- src/main/java/org/traccar/model/User.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index 2c582328e..c259e1413 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -53,7 +53,7 @@ public class Device extends GroupedModel implements Disableable, Schedulable { } public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; + this.uniqueId = uniqueId != null ? uniqueId.trim() : null; } public static final String STATUS_UNKNOWN = "unknown"; @@ -100,7 +100,7 @@ public class Device extends GroupedModel implements Disableable, Schedulable { } public void setPhone(String phone) { - this.phone = phone; + this.phone = phone != null ? phone.trim() : null; } private String model; diff --git a/src/main/java/org/traccar/model/Driver.java b/src/main/java/org/traccar/model/Driver.java index b9e023088..2689c67f2 100644 --- a/src/main/java/org/traccar/model/Driver.java +++ b/src/main/java/org/traccar/model/Driver.java @@ -38,7 +38,7 @@ public class Driver extends ExtendedModel { } public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; + this.uniqueId = uniqueId != null ? uniqueId.trim() : null; } } diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 53594fe07..0540f16d7 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -63,7 +63,7 @@ public class User extends ExtendedModel implements UserRestrictions, Disableable } public void setPhone(String phone) { - this.phone = phone; + this.phone = phone != null ? phone.trim() : null; } private boolean readonly; -- cgit v1.2.3 From 840d5600c69839e9be7a241d69005f322dfef124 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 19 Jul 2023 07:46:04 -0700 Subject: Remove unnecessary checks --- src/main/java/org/traccar/model/Device.java | 2 +- src/main/java/org/traccar/model/Driver.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index c259e1413..e07815976 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -53,7 +53,7 @@ public class Device extends GroupedModel implements Disableable, Schedulable { } public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId != null ? uniqueId.trim() : null; + this.uniqueId = uniqueId.trim(); } public static final String STATUS_UNKNOWN = "unknown"; diff --git a/src/main/java/org/traccar/model/Driver.java b/src/main/java/org/traccar/model/Driver.java index 2689c67f2..ca5714e51 100644 --- a/src/main/java/org/traccar/model/Driver.java +++ b/src/main/java/org/traccar/model/Driver.java @@ -38,7 +38,7 @@ public class Driver extends ExtendedModel { } public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId != null ? uniqueId.trim() : null; + this.uniqueId = uniqueId.trim(); } } -- cgit v1.2.3 From 8970e5ad49cbe9ad2ec106b2140cfc9f276ef7de Mon Sep 17 00:00:00 2001 From: Rodolfo Silva Date: Wed, 19 Jul 2023 21:38:33 -0300 Subject: change the year from the copyright text --- src/main/java/org/traccar/forward/EventForwarderAmqp.java | 2 +- src/main/java/org/traccar/forward/PositionForwarderAmqp.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/forward/EventForwarderAmqp.java b/src/main/java/org/traccar/forward/EventForwarderAmqp.java index 64edbe8a5..97f14d4ea 100644 --- a/src/main/java/org/traccar/forward/EventForwarderAmqp.java +++ b/src/main/java/org/traccar/forward/EventForwarderAmqp.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * 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. diff --git a/src/main/java/org/traccar/forward/PositionForwarderAmqp.java b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java index c55ca3d73..ea9e5c370 100644 --- a/src/main/java/org/traccar/forward/PositionForwarderAmqp.java +++ b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * 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. -- cgit v1.2.3 From dacaefcd4e416eeeedf1074729a8670aec1e53fb Mon Sep 17 00:00:00 2001 From: Rodolfo Silva Date: Wed, 19 Jul 2023 22:42:16 -0300 Subject: refactor the amqp client logic to have a separated class --- src/main/java/org/traccar/forward/AmqpClient.java | 57 ++++++++++++++++++++++ .../org/traccar/forward/EventForwarderAmqp.java | 49 +++---------------- .../org/traccar/forward/PositionForwarderAmqp.java | 48 +++--------------- 3 files changed, 73 insertions(+), 81 deletions(-) create mode 100644 src/main/java/org/traccar/forward/AmqpClient.java diff --git a/src/main/java/org/traccar/forward/AmqpClient.java b/src/main/java/org/traccar/forward/AmqpClient.java new file mode 100644 index 000000000..302aa664c --- /dev/null +++ b/src/main/java/org/traccar/forward/AmqpClient.java @@ -0,0 +1,57 @@ +/* + * 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.forward; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.MessageProperties; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeoutException; + +public class AmqpClient { + private final Channel channel; + private final String exchange; + private final String topic; + + AmqpClient(String connectionUrl, String exchange, String topic) { + this.exchange = exchange; + this.topic = topic; + + ConnectionFactory factory = new ConnectionFactory(); + try { + factory.setUri(connectionUrl); + } catch (NoSuchAlgorithmException | URISyntaxException | KeyManagementException e) { + throw new RuntimeException("Error while setting URI for RabbitMQ connection factory", e); + } + + try (Connection connection = factory.newConnection()) { + channel = connection.createChannel(); + channel.exchangeDeclare(exchange, BuiltinExchangeType.TOPIC, true); + } catch (IOException | TimeoutException e) { + throw new RuntimeException("Error while creating and configuring RabbitMQ channel", e); + } + } + + public void publishMessage(String message) throws IOException { + channel.basicPublish(exchange, topic, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); + } +} diff --git a/src/main/java/org/traccar/forward/EventForwarderAmqp.java b/src/main/java/org/traccar/forward/EventForwarderAmqp.java index 97f14d4ea..5c38a4459 100644 --- a/src/main/java/org/traccar/forward/EventForwarderAmqp.java +++ b/src/main/java/org/traccar/forward/EventForwarderAmqp.java @@ -15,64 +15,31 @@ */ package org.traccar.forward; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; + import org.traccar.config.Config; import org.traccar.config.Keys; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.Properties; -import java.util.concurrent.TimeoutException; public class EventForwarderAmqp implements EventForwarder { - private final Channel channel; + private final AmqpClient amqpClient; private final ObjectMapper objectMapper; - private final String exchange; - private final String topic; - public EventForwarderAmqp(Config config, ObjectMapper objectMapper) { - ConnectionFactory factory = new ConnectionFactory(); - try { - factory.setUri(config.getString(Keys.EVENT_FORWARD_URL)); - } catch (NoSuchAlgorithmException | URISyntaxException | KeyManagementException e) { - throw new RuntimeException(e); - } - - try { - Connection connection = factory.newConnection(); - exchange = config.getString(Keys.EVENT_FORWARD_EXCHANGE); - topic = config.getString(Keys.EVENT_FORWARD_TOPIC); - channel = connection.createChannel(); - channel.exchangeDeclare(exchange, "topic", true); - this.objectMapper = objectMapper; - } catch (IOException | TimeoutException e) { - throw new RuntimeException(e); - } + String connectionUrl = config.getString(Keys.EVENT_FORWARD_URL); + String exchange = config.getString(Keys.EVENT_FORWARD_EXCHANGE); + String topic = config.getString(Keys.EVENT_FORWARD_TOPIC); + this.objectMapper = objectMapper; + amqpClient = new AmqpClient(connectionUrl, exchange, topic); } @Override public void forward(EventData eventData, ResultHandler resultHandler) { try { String value = objectMapper.writeValueAsString(eventData); - - BasicProperties properties = new BasicProperties.Builder() - .contentType("application/json") - .contentEncoding("string") - .deliveryMode(2) - .priority(10) - .build(); - - channel.basicPublish(exchange, topic, properties, value.getBytes()); + amqpClient.publishMessage(value); resultHandler.onResult(true, null); } catch (IOException e) { resultHandler.onResult(false, e); diff --git a/src/main/java/org/traccar/forward/PositionForwarderAmqp.java b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java index ea9e5c370..3996bda15 100644 --- a/src/main/java/org/traccar/forward/PositionForwarderAmqp.java +++ b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java @@ -15,63 +15,31 @@ */ package org.traccar.forward; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; + import org.traccar.config.Config; import org.traccar.config.Keys; import java.io.IOException; -import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.Properties; -import java.util.concurrent.TimeoutException; public class PositionForwarderAmqp implements PositionForwarder { - private final Channel channel; + private final AmqpClient amqpClient; private final ObjectMapper objectMapper; - private final String exchange; - private final String topic; - public PositionForwarderAmqp(Config config, ObjectMapper objectMapper) { - ConnectionFactory factory = new ConnectionFactory(); - try { - factory.setUri(config.getString(Keys.FORWARD_URL)); - } catch (NoSuchAlgorithmException | URISyntaxException | KeyManagementException e) { - throw new RuntimeException(e); - } - - try { - Connection connection = factory.newConnection(); - topic = config.getString(Keys.FORWARD_TOPIC); - exchange = config.getString(Keys.EVENT_FORWARD_EXCHANGE); - channel = connection.createChannel(); - channel.exchangeDeclare(exchange, "topic", true); - this.objectMapper = objectMapper; - } catch (IOException | TimeoutException e) { - throw new RuntimeException(e); - } + String connectionUrl = config.getString(Keys.FORWARD_URL); + String exchange = config.getString(Keys.FORWARD_EXCHANGE); + String topic = config.getString(Keys.FORWARD_TOPIC); + amqpClient = new AmqpClient(connectionUrl, exchange, topic); + this.objectMapper = objectMapper; } @Override public void forward(PositionData positionData, ResultHandler resultHandler) { try { String value = objectMapper.writeValueAsString(positionData); - - BasicProperties properties = new BasicProperties.Builder() - .contentType("application/json") - .contentEncoding("string") - .deliveryMode(2) - .priority(10) - .build(); - - channel.basicPublish(exchange, topic, properties, value.getBytes()); + amqpClient.publishMessage(value); resultHandler.onResult(true, null); } catch (IOException e) { resultHandler.onResult(false, e); -- cgit v1.2.3 From 6631d7c4b3522e81af563e3ac82131a6e5c50b89 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 20 Jul 2023 06:48:50 -0700 Subject: Improve RF-V48 frame decoding --- .../java/org/traccar/protocol/WatchFrameDecoder.java | 16 ++++++++++++++-- .../java/org/traccar/protocol/WatchFrameDecoderTest.java | 4 ++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java index ec67aa34d..9dfae8726 100644 --- a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java @@ -27,9 +27,21 @@ public class WatchFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + int brackets = 0; int endIndex = -1; - for (int i = buf.writerIndex() - 1; i >= buf.readerIndex(); i--) { - if (buf.getByte(i) == ']') { + for (int i = buf.readerIndex(); i < buf.writerIndex(); i++) { + byte b = buf.getByte(i); + switch (b) { + case '[': + brackets += 1; + break; + case ']': + brackets -= 1; + break; + default: + break; + } + if (brackets == 0 && i > buf.readerIndex()) { endIndex = i + 1; break; } diff --git a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java index bf212544c..cb20e1b4d 100644 --- a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java @@ -10,6 +10,10 @@ public class WatchFrameDecoderTest extends ProtocolTest { var decoder = inject(new WatchFrameDecoder()); + verifyFrame( + binary("5b33472a393730353134313734302a303030392a4c4b2c302c302c35335d"), + decoder.decode(null, null, binary("5b33472a393730353134313734302a303030392a4c4b2c302c302c35335d5b33472a393730353134313734302a303035412a55442c3139303732332c3139303730372c412c33362e3831353130392c4e2c31302e313739323331322c452c382e32342c3132372e392c32312e302c352c3130302c35332c302c302c30303030303030302c302c302c35382e305d5b33472a393730353134313734302a303030332a544b515d5b33472a393730353134313734302a303030392a4c4b2c302c302c35335d"))); + verifyFrame( binary("5b33472a3838303930303234322a303133442a55442c3132303632332c3134303032302c412c34382e3934393237332c4e2c20342e333738333036302c452c31382e35362c34332e382c302e302c31322c3130302c37362c3232363132302c302c30303030303030302c322c3235352c3230342c382c333131302c35353032352c3134362c333133302c34393239372c3132342c352c42616e67696e67576966692c33343a61313a65643a65313a39313a34662c2d37312c42415220576946692c33363a61323a65313a65643a61313a64652c2d37322c4e6574776f726b576966692c32363a64653a61313a65643a65313a61302c2d37332c46696265722c33363a61313a65643a65313a39313a34662c2d37352c5b4c475f57616c6c2d4d6f756e7420412f435d653732352c36363a61313a65643a65313a65373a32352c2d38322c31352e305d"), decoder.decode(null, null, binary("5b33472a3838303930303234322a303133442a55442c3132303632332c3134303032302c412c34382e3934393237332c4e2c20342e333738333036302c452c31382e35362c34332e382c302e302c31322c3130302c37362c3232363132302c302c30303030303030302c322c3235352c3230342c382c333131302c35353032352c3134362c333133302c34393239372c3132342c352c42616e67696e67576966692c33343a61313a65643a65313a39313a34662c2d37312c42415220576946692c33363a61323a65313a65643a61313a64652c2d37322c4e6574776f726b576966692c32363a64653a61313a65643a65313a61302c2d37332c46696265722c33363a61313a65643a65313a39313a34662c2d37352c5b4c475f57616c6c2d4d6f756e7420412f435d653732352c36363a61313a65643a65313a65373a32352c2d38322c31352e305d"))); -- cgit v1.2.3 From c85df48c0ff76979839f62120fd311073e0c1d80 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 21 Jul 2023 07:39:24 -0700 Subject: Fix Fifotrack Q3 missing time --- src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java | 2 ++ src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index c30398d36..87587aa1e 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -242,6 +242,8 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { } else { + getLastLocation(position, position.getDeviceTime()); + String[] points = parser.next().split("\\|"); for (String point : points) { String[] wifi = point.split(":"); diff --git a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java index cbfc46703..77778d885 100644 --- a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class FifotrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new FifotrackProtocolDecoder(null)); + verifyAttributes(decoder, buffer( + "$$159,866344056951341,399D,A03,,230716222659,240|8|2724|20EEF33,4.20,100,003E,1,AE233FC0D2E0:-65|3E286D5FB6E8:-65|28BD890A4A0E:-67|8ED81B5DFC3A:-70|8AD81B5DFC3A:-70*5F")); + verifyAttribute(decoder, buffer( "$$99,865413050150407,7F,A03,,230626072722,460|0|25FC|AC2AB0B,3.74,52,0019,0,A,0,13,22.643466,114.018211*74"), Position.KEY_SATELLITES, 13); -- cgit v1.2.3 From a596ba5287375609adab2b7ba4de61fbc39a37a0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 22 Jul 2023 07:57:30 -0700 Subject: Add unit test --- src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index f0dd10772..3f8a4d0c2 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyNull(decoder, buffer( + "+RESP:GTFRI,8020040200,866314060109269,,,10,1,1,0.0,0,9.0,-71.596601,-33.524595,20230722145338,0730,0001,772A,052B253E,00,0.0,,,,,100,210100,,,,20230722145341,0F4C$")); + verifyAttributes(decoder, buffer( "+RESP:GTCAN,F1040C,862599050497393,GV350M,0,0,FFFFFFFF,,1,,,,,,,,,,,,,,,,,,,,,,,0,,,1,0.0,70,2961.6,-78.691750,-0.951135,20230703191659,,,,,,20230703191659,5A4A$")); -- cgit v1.2.3 From fc3c3ee38bdfd51ed1f56488661becffecceb3ef Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 23 Jul 2023 07:22:20 -0700 Subject: Device inactivity group config --- .../schedule/TaskDeviceInactivityCheck.java | 37 ++++++++++++++++++---- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java index 57c64dc5b..81567ec31 100644 --- a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java +++ b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.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. @@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory; import org.traccar.database.NotificationManager; import org.traccar.model.Device; import org.traccar.model.Event; +import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; @@ -31,6 +32,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class TaskDeviceInactivityCheck implements ScheduleTask { @@ -64,22 +66,45 @@ public class TaskDeviceInactivityCheck implements ScheduleTask { Map events = new HashMap<>(); try { + Map groups = storage.getObjects(Group.class, new Request(new Columns.All())) + .stream().collect(Collectors.toMap(Group::getId, group -> group)); for (Device device : storage.getObjects(Device.class, new Request(new Columns.All()))) { - if (device.getLastUpdate() != null && checkDevice(device, currentTime, checkPeriod)) { + if (device.getLastUpdate() != null && checkDevice(device, groups, currentTime, checkPeriod)) { Event event = new Event(Event.TYPE_DEVICE_INACTIVE, device.getId()); event.set(ATTRIBUTE_LAST_UPDATE, device.getLastUpdate().getTime()); events.put(event, null); } } } catch (StorageException e) { - LOGGER.warn("Get devices error", e); + LOGGER.warn("Database error", e); } notificationManager.updateEvents(events); } - private boolean checkDevice(Device device, long currentTime, long checkPeriod) { - long deviceInactivityStart = device.getLong(ATTRIBUTE_DEVICE_INACTIVITY_START); + private long getAttribute(Device device, Map groups, String key) { + long deviceValue = device.getLong(key); + if (deviceValue > 0) { + return deviceValue; + } else { + long groupId = device.getGroupId(); + while (groupId > 0) { + Group group = groups.get(groupId); + if (group == null) { + return 0; + } + long groupValue = group.getLong(key); + if (groupValue > 0) { + return groupValue; + } + groupId = group.getGroupId(); + } + return 0; + } + } + + private boolean checkDevice(Device device, Map groups, long currentTime, long checkPeriod) { + long deviceInactivityStart = getAttribute(device, groups, ATTRIBUTE_DEVICE_INACTIVITY_START); if (deviceInactivityStart > 0) { long timeThreshold = device.getLastUpdate().getTime() + deviceInactivityStart; if (currentTime >= timeThreshold) { @@ -88,7 +113,7 @@ public class TaskDeviceInactivityCheck implements ScheduleTask { return true; } - long deviceInactivityPeriod = device.getLong(ATTRIBUTE_DEVICE_INACTIVITY_PERIOD); + long deviceInactivityPeriod = getAttribute(device, groups, ATTRIBUTE_DEVICE_INACTIVITY_PERIOD); if (deviceInactivityPeriod > 0) { long count = (currentTime - timeThreshold - 1) / deviceInactivityPeriod; timeThreshold += count * deviceInactivityPeriod; -- cgit v1.2.3 From 6e5481ebb1858726604706d011e5c5f509ac5306 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 24 Jul 2023 07:26:18 -0700 Subject: Fix VL03 ignition decoding --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index f7cdd3920..d6d988423 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -345,7 +345,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { mnc = buf.readUnsignedByte(); } int lac; - if (type == MSG_LBS_ALARM) { + if (type == MSG_LBS_ALARM || type == MSG_GPS_LBS_7) { lac = buf.readInt(); } else { lac = buf.readUnsignedShort(); diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index cc71eb9bd..68579e815 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "787829a01707150f2d0ecd01635100041e96d000087c02d4020000912e000000000718798d000e0006ed3ce50d0a"), + Position.KEY_IGNITION, false); + verifyNotNull(decoder, binary( "787829a0170704112226cf0163fe7c0420f6f000091302d402000091290000000007186b8f01030001460d010d0a")); -- cgit v1.2.3 From 6cb4db1f6bb4f93ad42b013a38ace9a6a3b735f6 Mon Sep 17 00:00:00 2001 From: seym45 Date: Mon, 24 Jul 2023 01:25:05 +0400 Subject: Define command 'rollback' --- src/main/java/org/traccar/model/Command.java | 1 + .../java/org/traccar/protocol/GatorProtocol.java | 5 +++ .../org/traccar/protocol/GatorProtocolEncoder.java | 52 ++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/GatorProtocolEncoder.java diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index 99988dd82..e0c1c3976 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -45,6 +45,7 @@ public class Command extends BaseCommand { public static final String TYPE_SILENCE_TIME = "silenceTime"; public static final String TYPE_SET_PHONEBOOK = "setPhonebook"; public static final String TYPE_MESSAGE = "message"; + public static final String TYPE_ROLLCALL = "rollcall"; public static final String TYPE_VOICE_MESSAGE = "voiceMessage"; public static final String TYPE_OUTPUT_CONTROL = "outputControl"; public static final String TYPE_VOICE_MONITORING = "voiceMonitoring"; diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index 7341b69a3..c54b1b53d 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -20,6 +20,7 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.model.Command; import javax.inject.Inject; @@ -27,10 +28,14 @@ public class GatorProtocol extends BaseProtocol { @Inject public GatorProtocol(Config config) { + setSupportedDataCommands( + Command.TYPE_ROLLCALL + ); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2)); + pipeline.addLast(new GatorProtocolEncoder(GatorProtocol.this)); pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java new file mode 100644 index 000000000..452fde275 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023 - Hossain Mohammad Seym + * + * 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.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.config.Keys; +import org.traccar.helper.Checksum; +import org.traccar.helper.model.AttributeUtil; +import org.traccar.model.Command; +import org.traccar.model.Device; + +import java.nio.charset.StandardCharsets; + +public class GatorProtocolEncoder extends BaseProtocolEncoder { + + public GatorProtocolEncoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf encodeContent(long deviceId, String content) { + // FIXME: implement this method + return null; + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_ROLLCALL: + return encodeContent(command.getDeviceId(), "0x30"); + default: + return null; + } + } + +} -- cgit v1.2.3 From 1ee9e9396d7274f057f5e6d2d69e72ec1a5c0135 Mon Sep 17 00:00:00 2001 From: seym45 Date: Mon, 24 Jul 2023 20:15:47 +0400 Subject: Add method to encodeId --- .../org/traccar/protocol/GatorProtocolEncoder.java | 36 ++++++++++++++++++++-- .../traccar/protocol/GatorProtocolEncoderTest.java | 19 ++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 452fde275..df85a712c 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -21,6 +21,7 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.Protocol; import org.traccar.config.Keys; import org.traccar.helper.Checksum; +import org.traccar.helper.DataConverter; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; import org.traccar.model.Device; @@ -33,9 +34,38 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { super(protocol); } - private ByteBuf encodeContent(long deviceId, String content) { + + public static String encodeId(long deviceId) { + StringBuilder encodedId = new StringBuilder(); + + String imei = String.valueOf(deviceId); + String a = imei.substring(1, 3); + String b = imei.substring(3, 5); + String c = imei.substring(5, 7); + String d = imei.substring(7, 9); + String e = imei.substring(9); + String[] arr = {b, c, d, e}; + + String binaryFirstDigit = Integer.toBinaryString(Integer.valueOf(a) - 30); + binaryFirstDigit = String.format("%4s", binaryFirstDigit).replace(' ', '0'); + + for (int i = 0; i < 4; i++) { + int sum = Integer.parseInt(arr[i]) + Integer.parseInt(String.valueOf(binaryFirstDigit.charAt(i)) + "0000000", 2); + arr[i] = Integer.toHexString(sum).toUpperCase(); + arr[i] = String.format("%2s", arr[i]).replace(' ', '0'); + } + + for (String s : arr) { + encodedId.append(s); + } + + return encodedId.toString(); + } + + + private ByteBuf encodeContent(long deviceId, String mainOrder, String content) { // FIXME: implement this method - return null; + return null; } @Override @@ -43,7 +73,7 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { switch (command.getType()) { case Command.TYPE_ROLLCALL: - return encodeContent(command.getDeviceId(), "0x30"); + return encodeContent(command.getDeviceId(), "30", null); default: return null; } diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java new file mode 100644 index 000000000..7e8f51008 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class GatorProtocolEncoderTest extends ProtocolTest { + + @Test + void encodeId() throws Exception { + var encoder = inject(new GatorProtocolEncoder(null)); + assertEquals("2008958C", encoder.encodeId(13332082112L)); + + } +} -- cgit v1.2.3 From 09daf15be1a874a8880645d4595e1b57d4cf2eee Mon Sep 17 00:00:00 2001 From: seym45 Date: Mon, 24 Jul 2023 20:29:29 +0400 Subject: Add method to get calibration byte --- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index df85a712c..0d4353c8f 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -62,12 +62,24 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { return encodedId.toString(); } + private static String getCalibrationByteFromHexString(String data) { + String response = ""; + int calib = 0; + int length = data.length() / 2; + for (int i = 0; i < length; i++) { + calib = calib ^ Integer.parseInt(data.substring(i * 2, i * 2 + 2), 16); + } + response = Integer.toHexString(calib).toUpperCase(); + response = String.format("%2s", response).replace(' ', '0'); + return response; + } private ByteBuf encodeContent(long deviceId, String mainOrder, String content) { // FIXME: implement this method return null; } + @Override protected Object encodeCommand(Command command) { -- cgit v1.2.3 From 103fbde721753b8be65c39e0e9118943c6bebc68 Mon Sep 17 00:00:00 2001 From: seym45 Date: Mon, 24 Jul 2023 20:34:00 +0400 Subject: Add Gator content encoder and test snippets --- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 10 ++++++++-- .../java/org/traccar/protocol/GatorProtocolEncoderTest.java | 12 +++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 0d4353c8f..125031eee 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -75,8 +75,14 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { } private ByteBuf encodeContent(long deviceId, String mainOrder, String content) { - // FIXME: implement this method - return null; + String pseudoIPAddress = encodeId(deviceId); + int length = 4 + 1 + 1; // ip 4 bytes, calibration byte and end byte + String hexStringLength = String.format("%02X", length); + + String packet = "2424" + mainOrder + "00" + hexStringLength + pseudoIPAddress; + String calibration = getCalibrationByteFromHexString(packet); + packet = packet + calibration + "0D"; + return Unpooled.wrappedBuffer(DataConverter.parseHex(packet)); } diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index 7e8f51008..74ac35440 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -4,16 +4,22 @@ import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; -import java.nio.charset.StandardCharsets; - import static org.junit.jupiter.api.Assertions.assertEquals; public class GatorProtocolEncoderTest extends ProtocolTest { @Test - void encodeId() throws Exception { + void encodeId() throws Exception { var encoder = inject(new GatorProtocolEncoder(null)); assertEquals("2008958C", encoder.encodeId(13332082112L)); + } + @Test + public void testEncode() throws Exception { + var encoder = inject(new GatorProtocolEncoder(null)); + Command command = new Command(); + command.setDeviceId(13332082112L); + command.setType(Command.TYPE_ROLLCALL); + verifyCommand(encoder, command, binary("24243000062008958C070D")); } } -- cgit v1.2.3 From 8c227973608eee7ba5519f22c5781f912dd4e9b5 Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 25 Jul 2023 10:56:55 +0400 Subject: Change command type --- src/main/java/org/traccar/model/Command.java | 1 - src/main/java/org/traccar/protocol/GatorProtocol.java | 2 +- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 4 ++-- src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index e0c1c3976..99988dd82 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -45,7 +45,6 @@ public class Command extends BaseCommand { public static final String TYPE_SILENCE_TIME = "silenceTime"; public static final String TYPE_SET_PHONEBOOK = "setPhonebook"; public static final String TYPE_MESSAGE = "message"; - public static final String TYPE_ROLLCALL = "rollcall"; public static final String TYPE_VOICE_MESSAGE = "voiceMessage"; public static final String TYPE_OUTPUT_CONTROL = "outputControl"; public static final String TYPE_VOICE_MONITORING = "voiceMonitoring"; diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index c54b1b53d..bb0e017f4 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -29,7 +29,7 @@ public class GatorProtocol extends BaseProtocol { @Inject public GatorProtocol(Config config) { setSupportedDataCommands( - Command.TYPE_ROLLCALL + Command.TYPE_POSITION_SINGLE ); addServer(new TrackerServer(config, getName(), false) { @Override diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 125031eee..efe8715e3 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -90,11 +90,11 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { protected Object encodeCommand(Command command) { switch (command.getType()) { - case Command.TYPE_ROLLCALL: + // According to Protocol Documentation, 0x30 is for rollcall command + case Command.TYPE_POSITION_SINGLE: return encodeContent(command.getDeviceId(), "30", null); default: return null; } } - } diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index 74ac35440..04fce0ac8 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -19,7 +19,7 @@ public class GatorProtocolEncoderTest extends ProtocolTest { var encoder = inject(new GatorProtocolEncoder(null)); Command command = new Command(); command.setDeviceId(13332082112L); - command.setType(Command.TYPE_ROLLCALL); + command.setType(Command.TYPE_POSITION_SINGLE); verifyCommand(encoder, command, binary("24243000062008958C070D")); } } -- cgit v1.2.3 From 1a1126d2d39220f3f28d98662a8c3d5fd4c1cfee Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 25 Jul 2023 05:15:13 -0700 Subject: Handle ST410 no GPS data --- .../traccar/protocol/SuntechProtocolDecoder.java | 26 ++++++++++++++-------- .../protocol/SuntechProtocolDecoderTest.java | 3 +++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 047a1822a..86a8bf6fe 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -271,18 +271,26 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { index += 1; // collaborative network } - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(values[index++] + values[index++])); + if (values[index].isEmpty()) { - position.setLatitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Double.parseDouble(values[index++])); + getLastLocation(position, null); - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + } else { - position.setValid(values[index++].equals("1")); + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(values[index++] + values[index++])); + + position.setLatitude(Double.parseDouble(values[index++])); + position.setLongitude(Double.parseDouble(values[index++])); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + position.setCourse(Double.parseDouble(values[index++])); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + + position.setValid(values[index++].equals("1")); + + } return position; } diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index 884f13350..cbb68132f 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -12,6 +12,9 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { var decoder = inject(new SuntechProtocolDecoder(null)); + verifyAttributes(decoder, buffer( + "ST410STT;109815653;445;03;16531;724;10;-77;6011;7;16273;724;10;7511;0;0;13903;724;10;6011;0;0;7671;724;10;7111;0;0;16533;724;10;6011;0;0;0;0;0;0;0;0;0;0;0;0;0;0;3.86;0;0098;1;003;;;;;;;;;")); + verifyPosition(decoder, buffer( "ALT;0840037569;FFFFFF;84;1.0.6;0;20221228;11:33:05;00004490;724;11;05D3;33;-22.845935;-46.322000;0.00;0.00;18;0;00000001;00000000;99;;;;08E3800F;4.1;12.37;0;0;0;0;4;;;;")); -- cgit v1.2.3 From 413d9a49c41a27a221f2350e5cd4864c1231bb50 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 25 Jul 2023 05:41:16 -0700 Subject: Decode HS-5000G odometer value --- src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java | 9 ++++++--- .../java/org/traccar/protocol/HuaShengProtocolDecoderTest.java | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 1ad27be5f..7d634b0f2 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -229,7 +229,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.setCourse(buf.readUnsignedShort()); position.setAltitude(buf.readUnsignedShort()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); + buf.readUnsignedShort(); // odometer speed Network network = new Network(); @@ -264,8 +264,11 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedInt(); // run time break; case 0x0009: - position.set( - Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + position.set(Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + break; + case 0x0010: + position.set(Position.KEY_ODOMETER, Double.parseDouble( + buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()) * 1000); break; case 0x0011: position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 0.05); diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java index a54fa53c6..d8cc739ab 100644 --- a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java @@ -20,6 +20,10 @@ public class HuaShengProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "c000000077aa0200000000000e000100143347315f48312e315f56312e30372e54000300133335353835353035303434303635380004000b3531323030303000050005010006000400070004000800050000090018383936313032353431343533333239313833360d000a000f796573696e7465726e6574c0")); + verifyAttribute(decoder, binary( + "c0000000bdaa0000000000061d480000083233303132333039323634330000000000000000000000a600140000000100187e02de0a00290372000005951600260000004a0000040009080000004a0005000a0d0000000ad0000900154d414b474d363639484a4e333031383739000f00133836323230353035353338393836320010001031333231322e30303030303000110008000000000014000bf851084f000018001500060000002000153430344030354035363532403130363332c0"), + Position.KEY_ODOMETER, 13212000.0); + verifyNotNull(decoder, binary( "c0000000b9aa00000000000013c800001132333035303431343537323600186bc30045e5b8002a008b0077002d000100187f0c4b2600d906ec000005938800000000000e0000040009110000000e0005000a1d0400000079000900154646464646464646464646464646464646000f00133836323230353035353339313733360010000c302e30303030303000110008000000000014000bf81b204901b52a001500060000002000153231394030324030403130343438393139c0")); -- cgit v1.2.3 From 6ac15f2c6fb8798c6906c24e97b0048736270215 Mon Sep 17 00:00:00 2001 From: seym45 Date: Wed, 26 Jul 2023 03:02:34 +0400 Subject: Format code structure --- src/main/java/org/traccar/protocol/GatorProtocol.java | 4 +--- src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index bb0e017f4..46862f583 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -28,9 +28,7 @@ public class GatorProtocol extends BaseProtocol { @Inject public GatorProtocol(Config config) { - setSupportedDataCommands( - Command.TYPE_POSITION_SINGLE - ); + setSupportedDataCommands(Command.TYPE_POSITION_SINGLE); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index 04fce0ac8..a3bc3af2b 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -9,7 +9,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class GatorProtocolEncoderTest extends ProtocolTest { @Test - void encodeId() throws Exception { + void testEncodeId() throws Exception { var encoder = inject(new GatorProtocolEncoder(null)); assertEquals("2008958C", encoder.encodeId(13332082112L)); } -- cgit v1.2.3 From 2407799dc370d741431cbec056c0f2acbe454bf3 Mon Sep 17 00:00:00 2001 From: seym45 Date: Wed, 26 Jul 2023 04:11:40 +0400 Subject: Refactor method encodeId and encodeContent - Replace method getCalibrationByteFromHexString with xor checksum - Rewrite method encodeContent with ByteBuf instead of String - Refactor encodeId by replacing short variable names and use ByteBuf --- .../org/traccar/protocol/GatorProtocolEncoder.java | 83 ++++++++++------------ .../traccar/protocol/GatorProtocolEncoderTest.java | 9 ++- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index efe8715e3..296ff4f13 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 - Hossain Mohammad Seym + * Copyright 2023 Hossain Mohammad Seym (seym45@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,14 +19,11 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.Protocol; -import org.traccar.config.Keys; import org.traccar.helper.Checksum; -import org.traccar.helper.DataConverter; -import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; -import org.traccar.model.Device; -import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; public class GatorProtocolEncoder extends BaseProtocolEncoder { @@ -34,65 +31,57 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { super(protocol); } + public static ByteBuf encodeId(long deviceId) { + ByteBuf buf = Unpooled.buffer(); - public static String encodeId(long deviceId) { - StringBuilder encodedId = new StringBuilder(); - - String imei = String.valueOf(deviceId); - String a = imei.substring(1, 3); - String b = imei.substring(3, 5); - String c = imei.substring(5, 7); - String d = imei.substring(7, 9); - String e = imei.substring(9); - String[] arr = {b, c, d, e}; + String deviceIdStrVal = String.valueOf(deviceId); + List partialDigits = new ArrayList<>(); + for (int i = 1; i < deviceIdStrVal.length(); i += 2) { + partialDigits.add(deviceIdStrVal.substring(i, i + 2)); + } - String binaryFirstDigit = Integer.toBinaryString(Integer.valueOf(a) - 30); - binaryFirstDigit = String.format("%4s", binaryFirstDigit).replace(' ', '0'); + int firstDigit = Integer.parseInt(partialDigits.get(0)) - 30; - for (int i = 0; i < 4; i++) { - int sum = Integer.parseInt(arr[i]) + Integer.parseInt(String.valueOf(binaryFirstDigit.charAt(i)) + "0000000", 2); - arr[i] = Integer.toHexString(sum).toUpperCase(); - arr[i] = String.format("%2s", arr[i]).replace(' ', '0'); - } + for (int i = 1; i < partialDigits.size(); i++) { + int shiftCount = 4 - i; + int addend = ((firstDigit & (1 << shiftCount)) >> shiftCount) << 7; + int sum = Integer.parseInt(partialDigits.get(i)) | addend; - for (String s : arr) { - encodedId.append(s); + buf.writeByte(sum); } - return encodedId.toString(); + return buf; } - private static String getCalibrationByteFromHexString(String data) { - String response = ""; - int calib = 0; - int length = data.length() / 2; - for (int i = 0; i < length; i++) { - calib = calib ^ Integer.parseInt(data.substring(i * 2, i * 2 + 2), 16); - } - response = Integer.toHexString(calib).toUpperCase(); - response = String.format("%2s", response).replace(' ', '0'); - return response; - } - private ByteBuf encodeContent(long deviceId, String mainOrder, String content) { - String pseudoIPAddress = encodeId(deviceId); + private ByteBuf encodeContent(long deviceId, int mainOrder) { + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte(0x24); + buf.writeByte(0x24); + buf.writeByte(mainOrder); + buf.writeByte(0x00); + int length = 4 + 1 + 1; // ip 4 bytes, calibration byte and end byte - String hexStringLength = String.format("%02X", length); + buf.writeByte(length); - String packet = "2424" + mainOrder + "00" + hexStringLength + pseudoIPAddress; - String calibration = getCalibrationByteFromHexString(packet); - packet = packet + calibration + "0D"; - return Unpooled.wrappedBuffer(DataConverter.parseHex(packet)); - } + ByteBuf pseudoIPAddress = encodeId(deviceId); + buf.writeBytes(pseudoIPAddress); + + int checksum = Checksum.xor(buf.nioBuffer()); + buf.writeByte(checksum); + buf.writeByte(0x0D); + + return buf; + } @Override protected Object encodeCommand(Command command) { switch (command.getType()) { - // According to Protocol Documentation, 0x30 is for rollcall command case Command.TYPE_POSITION_SINGLE: - return encodeContent(command.getDeviceId(), "30", null); + return encodeContent(command.getDeviceId(), 0x30); default: return null; } diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index a3bc3af2b..babd7285d 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -1,5 +1,7 @@ package org.traccar.protocol; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; @@ -11,7 +13,12 @@ public class GatorProtocolEncoderTest extends ProtocolTest { @Test void testEncodeId() throws Exception { var encoder = inject(new GatorProtocolEncoder(null)); - assertEquals("2008958C", encoder.encodeId(13332082112L)); + ByteBuf pseudoId = Unpooled.buffer(); + pseudoId.writeByte(0x20); + pseudoId.writeByte(0x08); + pseudoId.writeByte(0x95); + pseudoId.writeByte(0x8C); + assertEquals(pseudoId, encoder.encodeId(13332082112L)); } @Test -- cgit v1.2.3 From 9b680956acccb5bd64b6c9c6eee1428e93387719 Mon Sep 17 00:00:00 2001 From: seym45 Date: Wed, 26 Jul 2023 04:21:23 +0400 Subject: Remove extra line --- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 296ff4f13..c4f06dbc5 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -53,7 +53,6 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { return buf; } - private ByteBuf encodeContent(long deviceId, int mainOrder) { ByteBuf buf = Unpooled.buffer(); -- cgit v1.2.3 From 18c1e761fd203c994445ac85e808ca6f672d0ec5 Mon Sep 17 00:00:00 2001 From: seym45 Date: Wed, 26 Jul 2023 11:11:15 +0400 Subject: Resolve suggestions - Define MSG_POSITION_REQUEST - Change comment "calibration" to "checksum" --- src/main/java/org/traccar/protocol/GatorProtocolDecoder.java | 1 + src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index 644caee81..f7da5dc75 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -37,6 +37,7 @@ 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_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 c4f06dbc5..f2c522067 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -60,9 +60,7 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { buf.writeByte(0x24); buf.writeByte(mainOrder); buf.writeByte(0x00); - - int length = 4 + 1 + 1; // ip 4 bytes, calibration byte and end byte - buf.writeByte(length); + buf.writeByte(4 + 1 + 1); // ip 4 bytes, checksum and end byte ByteBuf pseudoIPAddress = encodeId(deviceId); buf.writeBytes(pseudoIPAddress); @@ -80,7 +78,7 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { switch (command.getType()) { case Command.TYPE_POSITION_SINGLE: - return encodeContent(command.getDeviceId(), 0x30); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST); default: return null; } -- cgit v1.2.3 From fb4db390187fbfcf1220dc05fa03565799a829e8 Mon Sep 17 00:00:00 2001 From: seym45 Date: Thu, 27 Jul 2023 02:19:03 +0400 Subject: Simplify encodeId method for Gator Protocol --- .../org/traccar/protocol/GatorProtocolEncoder.java | 28 +++++++--------------- .../traccar/protocol/GatorProtocolEncoderTest.java | 12 ++++++++-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index f2c522067..3d38b7455 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -22,43 +22,33 @@ import org.traccar.Protocol; import org.traccar.helper.Checksum; import org.traccar.model.Command; -import java.util.ArrayList; -import java.util.List; - public class GatorProtocolEncoder extends BaseProtocolEncoder { public GatorProtocolEncoder(Protocol protocol) { super(protocol); } - public static ByteBuf encodeId(long deviceId) { + public ByteBuf encodeId(long deviceId) { ByteBuf buf = Unpooled.buffer(); - String deviceIdStrVal = String.valueOf(deviceId); - List partialDigits = new ArrayList<>(); - for (int i = 1; i < deviceIdStrVal.length(); i += 2) { - partialDigits.add(deviceIdStrVal.substring(i, i + 2)); - } - - int firstDigit = Integer.parseInt(partialDigits.get(0)) - 30; + String id = getUniqueId(deviceId); - for (int i = 1; i < partialDigits.size(); i++) { - int shiftCount = 4 - i; - int addend = ((firstDigit & (1 << shiftCount)) >> shiftCount) << 7; - int sum = Integer.parseInt(partialDigits.get(i)) | addend; + int firstDigit = Integer.parseInt(id.substring(1, 3)) - 30; - buf.writeByte(sum); - } + buf.writeByte(Integer.parseInt(id.substring(3, 5)) | (((firstDigit >> 3) & 1) << 7)); + buf.writeByte(Integer.parseInt(id.substring(5, 7)) | (((firstDigit >> 2) & 1) << 7)); + buf.writeByte(Integer.parseInt(id.substring(7, 9)) | (((firstDigit >> 1) & 1) << 7)); + buf.writeByte(Integer.parseInt(id.substring(9)) | ((firstDigit & 1) << 7)); return buf; } - private ByteBuf encodeContent(long deviceId, int mainOrder) { + private ByteBuf encodeContent(long deviceId, int type) { ByteBuf buf = Unpooled.buffer(); buf.writeByte(0x24); buf.writeByte(0x24); - buf.writeByte(mainOrder); + buf.writeByte(type); buf.writeByte(0x00); buf.writeByte(4 + 1 + 1); // ip 4 bytes, checksum and end byte diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index babd7285d..3f8fe2451 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -5,27 +5,35 @@ import io.netty.buffer.Unpooled; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; +import org.traccar.model.Device; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; public class GatorProtocolEncoderTest extends ProtocolTest { @Test void testEncodeId() throws Exception { var encoder = inject(new GatorProtocolEncoder(null)); + var device = encoder.getCacheManager().getObject(Device.class, 1); + when(device.getUniqueId()).thenReturn("13332082112"); + ByteBuf pseudoId = Unpooled.buffer(); pseudoId.writeByte(0x20); pseudoId.writeByte(0x08); pseudoId.writeByte(0x95); pseudoId.writeByte(0x8C); - assertEquals(pseudoId, encoder.encodeId(13332082112L)); + assertEquals(pseudoId, encoder.encodeId(1)); } @Test public void testEncode() throws Exception { var encoder = inject(new GatorProtocolEncoder(null)); + var device = encoder.getCacheManager().getObject(Device.class, 1); + when(device.getUniqueId()).thenReturn("13332082112"); + Command command = new Command(); - command.setDeviceId(13332082112L); + command.setDeviceId(1); command.setType(Command.TYPE_POSITION_SINGLE); verifyCommand(encoder, command, binary("24243000062008958C070D")); } -- cgit v1.2.3 From 1dfc61e3e981a23060d02c46451b19a600a87fa0 Mon Sep 17 00:00:00 2001 From: seym45 Date: Thu, 27 Jul 2023 11:27:44 +0400 Subject: Remove explicit test encodeId - encodeId tested inside testEncode --- .../org/traccar/protocol/GatorProtocolEncoderTest.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index 3f8fe2451..af6c71e37 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -1,31 +1,14 @@ package org.traccar.protocol; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; import org.traccar.model.Command; import org.traccar.model.Device; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; public class GatorProtocolEncoderTest extends ProtocolTest { - @Test - void testEncodeId() throws Exception { - var encoder = inject(new GatorProtocolEncoder(null)); - var device = encoder.getCacheManager().getObject(Device.class, 1); - when(device.getUniqueId()).thenReturn("13332082112"); - - ByteBuf pseudoId = Unpooled.buffer(); - pseudoId.writeByte(0x20); - pseudoId.writeByte(0x08); - pseudoId.writeByte(0x95); - pseudoId.writeByte(0x8C); - assertEquals(pseudoId, encoder.encodeId(1)); - } - @Test public void testEncode() throws Exception { var encoder = inject(new GatorProtocolEncoder(null)); -- cgit v1.2.3 From d4db066c6e0295a4c8646d82a982cd82e42c84c4 Mon Sep 17 00:00:00 2001 From: Mohamed Khalil HADDED Date: Sat, 29 Jul 2023 00:55:09 +0100 Subject: Watch Protocol Decoder update --- src/main/java/org/traccar/protocol/WatchProtocolDecoder.java | 7 +++++-- src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java index 40d56b130..b586f4e92 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java @@ -51,7 +51,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { .number("(dd)(dd)(dd),") // time (hhmmss) .expression("([AV]),") // validity .number(" *(-?d+.d+),") // latitude - .expression("([NS]),") + .expression("([NS])?,") .number(" *(-?d+.d+),") // longitude .expression("([EW])?,") .number("(d+.?d*),") // speed @@ -285,7 +285,8 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { || type.equalsIgnoreCase("BLOOD") || type.equalsIgnoreCase("BPHRT") || type.equalsIgnoreCase("TEMP") - || type.equalsIgnoreCase("btemp2")) { + || type.equalsIgnoreCase("btemp2") + || type.equalsIgnoreCase("oxygen")) { if (buf.isReadable()) { @@ -303,6 +304,8 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { if (Integer.parseInt(values[valueIndex++]) > 0) { position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(values[valueIndex])); } + } else if (type.equalsIgnoreCase("oxygen")) { + position.set("bloodOxygen", Integer.parseInt(values[++valueIndex])); } else { if (type.equalsIgnoreCase("BPHRT") || type.equalsIgnoreCase("BLOOD")) { position.set("pressureHigh", values[valueIndex++]); diff --git a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java index 855b9792c..5fd0ede44 100644 --- a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java @@ -17,6 +17,13 @@ public class WatchProtocolDecoderTest extends ProtocolTest { var decoder = inject(new WatchProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "[3G*9705141740*000B*oxygen,0,98]"), + "bloodOxygen", 98); + + verifyPosition(decoder, buffer( + "[3G*9705141740*00C2*UD_LTE,260723,185105,V,00.000000,,00.0000000,,0.00,0.0,0.0,0,100,67,0,0,00000000,2,0,605,1,10006,65799,14,10020,4104,4,3,,34:60:f9:ec:19:f8,-82,,98:48:27:55:18:20,-96,,34:e8:94:e4:06:18,-104,0.0]")); + verifyPosition(decoder, buffer( "[SG*9059011020*0067*AL,240123,181628,V,54.427538,N,6.409275,W,0.00,0,0,0,19,90,0,0,00000000,1,1,234,10,55C0,3B882A2,132,,10]")); -- cgit v1.2.3 From 230f629c3dce039aa8856fe2fb4c447a086d72e4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 3 Aug 2023 21:06:41 -0700 Subject: Handle invalid Ruptela GPS (fix #5152) --- .../traccar/protocol/RuptelaProtocolDecoder.java | 26 +++++++++++++--------- .../protocol/RuptelaProtocolDecoderTest.java | 3 +++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 2122d5081..649de7c5c 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -248,17 +248,21 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // priority (reserved) - position.setValid(true); - position.setLongitude(buf.readInt() / 10000000.0); - position.setLatitude(buf.readInt() / 10000000.0); - position.setAltitude(buf.readUnsignedShort() / 10.0); - position.setCourse(buf.readUnsignedShort() / 100.0); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - - position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); + int longitude = buf.readInt(); + int latitude = buf.readInt(); + if (longitude > Integer.MIN_VALUE && latitude > Integer.MIN_VALUE) { + position.setValid(true); + position.setLongitude(longitude / 10000000.0); + position.setLatitude(latitude / 10000000.0); + position.setAltitude(buf.readUnsignedShort() / 10.0); + position.setCourse(buf.readUnsignedShort() / 100.0); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); + } else { + buf.skipBytes(8); + getLastLocation(position, null); + } if (type == MSG_EXTENDED_RECORDS) { position.set(Position.KEY_EVENT, buf.readUnsignedShort()); diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java index f214ce5f8..e98dffdef 100644 --- a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class RuptelaProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "002e000316d53d58d6020f4573303430302e30332e36382e30340000c2b3090d0e950000827b000003e80000003c003c1681")); + verifyPositions(decoder, false, binary( + "03fb0003137ca79f856d01011d386d438b000080000000800000008000ffffffffffff070220211bff011d30c50000386d438b000080000000800000008000ffffffffffff0702201f1bff011d30c30000386d43a9000180000000800000008000ffffffffffffad0320211b16ad01011d30950000386d43c7000080000000800000008000ffffffffffff070220211b00011d30a60000386d4403000080000000800000008000ffffffffffff070220221b00011d30ae0000386d443f000080000000800000008000ffffffffffff070220231b00011d30ae000064c692cb000080000000800000008000ffffffffffff070220231b18011d3091000064c69306000080000000800000008000ffffffffffff070220231b14011d30a7000064c69322000180000000800000008000ffffffffffffad0320241b14ad00011d30a3000064c69342000080000000800000008000ffffffffffff070220241b13011d30ad000064c6934a000180000000800000008000ffffffffffffad0320241b10ad01011d30c3000064c6937e000080000000800000008000ffffffffffff070220241b12011d3092000064c6938b000180000000800000008000ffffffffffffad0320241b12ad00011d30bd000064c69395000180000000800000008000ffffffffffffad0320241b10ad01011d30a6000064c693ba000080000000800000008000ffffffffffff070220251b17011d30a2000064c693d4000180000000800000008000ffffffffffffad0320251b17ad00011d30cc000064c693f6000080000000800000008000ffffffffffff070220251b15011d3090000064c69404000180000000800000008000ffffffffffffad0320251b16ad01011d30a9000064c69432000080000000800000008000ffffffffffff070220261b14011d30be000064c6946d000180000000800000008000ffffffffffffad0320261b15ad00011d30b1000064c6946e000080000000800000008000ffffffffffff070220261b15011d3096000064c694aa000080000000800000008000ffffffffffff070220261b15011d30a8000064c694b2000180000000800000008000ffffffffffffad0320261b15ad01011d30a5000064c694e6000080000000800000008000ffffffffffff070220261b17011d309a000064c694f5000180000000800000008000ffffffffffffad0320261b17ad00011d309c000064c694f6000180000000800000008000ffffffffffffad0320261b17ad01011d3099000064c69522000080000000800000008000ffffffffffff070220261b14011d3094000064c6955e000080000000800000008000ffffffffffff070220261b15011d30b2000064c6959a000080000000800000008000ffffffffffff070220261b14011d30970000ad9e")); + verifyPositions(decoder, binary( "00800003167d765c155d01000160cd0a310000faae43f7176ee45702332b0c12000006070d05007300cfff260082008600870088000f00d7021100d801c900061d0000c500001e0e988300008900008b000002d0000c9bca720c889a0b047e00000000000000007f0000000000000000800000000000000000810000000000000000a341")); -- cgit v1.2.3 From 95fdfd770130b774e6201ddc88bba9241c95e3cc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 3 Aug 2023 21:17:52 -0700 Subject: Fix GT06 protocol conflict --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 7 ------- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index d6d988423..4762fc884 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -836,11 +836,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } } - if (type == MSG_STATUS && variant == Variant.VXT01) { - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - } - if (type == MSG_GPS_LBS_1) { if (variant == Variant.GT06E_CARD) { position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); @@ -1421,8 +1416,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.VXT01; } else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_1 && length == 0x24) { variant = Variant.VXT01; - } else if (header == 0x7878 && type == MSG_STATUS && length == 0x0a) { - variant = Variant.VXT01; } else if (header == 0x7878 && type == MSG_LBS_MULTIPLE_3 && length == 0x31) { variant = Variant.WANWAY_S20; } else if (header == 0x7878 && type == MSG_LBS_MULTIPLE_3 && length == 0x2e) { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 68579e815..40f268a9d 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -34,7 +34,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyAttribute(decoder, binary( "78780a130604ea04000006bc8a0d0a"), - Position.KEY_POWER, 0.0); + Position.KEY_POWER, null); verifyAttributes(decoder, binary( "797900849404414c4d313d43353b414c4d323d43433b414c4d333d35433b535441313d43303b4459443d30313b534f533d303133323838333730302c2c3b43454e5445523d303133323838333730303b46454e43453d46656e63652c4f46462c302c302e3030303030302c302e3030303030302c3330302c494e206f72204f55542c313b00b79d120d0a")); -- cgit v1.2.3 From d979ab718ff043c6ec6b815e9833621b9fe0e566 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 4 Aug 2023 17:12:49 -0700 Subject: Support JC400 alarm messages --- .../org/traccar/protocol/Gt06ProtocolDecoder.java | 37 ++++++++++++++++++---- .../traccar/protocol/Gt06ProtocolDecoderTest.java | 4 +++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 4762fc884..53c812bb7 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -121,6 +121,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { STANDARD, OBD6, WETRUST, + JC400, } private Variant variant; @@ -269,12 +270,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } public static boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) { - return decodeGps(position, buf, hasLength, true, true, timezone); + return decodeGps(position, buf, hasLength, true, true, false, timezone); } public static boolean decodeGps( Position position, ByteBuf buf, boolean hasLength, boolean hasSatellites, - boolean hasSpeed, TimeZone timezone) { + boolean hasSpeed, boolean longSpeed, TimeZone timezone) { DateBuilder dateBuilder = new DateBuilder(timezone) .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) @@ -293,7 +294,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { double longitude = buf.readUnsignedInt() / 60.0 / 30000.0; if (hasSpeed) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setSpeed(UnitsConverter.knotsFromKph( + longSpeed ? buf.readUnsignedShort() : buf.readUnsignedByte())); } int flags = buf.readUnsignedShort(); @@ -928,24 +930,44 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { boolean extendedAlarm = dataLength > 7; if (extendedAlarm) { - decodeGps(position, buf, false, false, false, deviceSession.get(DeviceSession.KEY_TIMEZONE)); + if (variant == Variant.JC400) { + buf.readUnsignedShort(); // marker + buf.readUnsignedByte(); // version + } + decodeGps( + position, buf, false, + variant == Variant.JC400, variant == Variant.JC400, variant == Variant.JC400, + deviceSession.get(DeviceSession.KEY_TIMEZONE)); } else { DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE)) .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); getLastLocation(position, dateBuilder.getDate()); } - short alarmType = buf.readUnsignedByte(); - switch (alarmType) { + if (variant == Variant.JC400) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); + } + short event = buf.readUnsignedByte(); + position.set(Position.KEY_EVENT, event); + switch (event) { case 0x01: position.set(Position.KEY_ALARM, extendedAlarm ? Position.ALARM_SOS : Position.ALARM_GENERAL); break; + case 0x0E: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + case 0x76: + position.set(Position.KEY_ALARM, Position.ALARM_TEMPERATURE); + break; case 0x80: position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); break; case 0x87: position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); break; + case 0x88: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; case 0x90: position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); break; @@ -959,7 +981,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); break; default: - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); break; } @@ -1432,6 +1453,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.OBD6; } else if (header == 0x7878 && type == MSG_GPS_LBS_1 && length == 0x29) { variant = Variant.WETRUST; + } else if (header == 0x7878 && type == MSG_ALARM && buf.getUnsignedShort(buf.readerIndex() + 4) == 0xffff) { + variant = Variant.JC400; } else { variant = Variant.STANDARD; } diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 40f268a9d..9b196e501 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78785995ffff01170719152013df0163d45f041ee52018be002f00876900004556454e545f3836323739383035303137353131325f30303030303030305f323032335f30375f32355f31385f33325f30355f31342e6d70340119d15a0d0a"), + Position.KEY_EVENT, 0x69); + verifyAttribute(decoder, binary( "787829a01707150f2d0ecd01635100041e96d000087c02d4020000912e000000000718798d000e0006ed3ce50d0a"), Position.KEY_IGNITION, false); -- cgit v1.2.3 From 8ab9cd75aad4a0940936304f055e155d87b03760 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 5 Aug 2023 07:15:07 -0700 Subject: Update API docs --- swagger.json | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/swagger.json b/swagger.json index eec852ac7..ccd26d4e8 100644 --- a/swagger.json +++ b/swagger.json @@ -2965,39 +2965,43 @@ "properties": { "userId": { "type": "integer", - "description": "User Id, can be only first parameter" + "description": "User id, can be only first parameter" }, "deviceId": { "type": "integer", - "description": "Device Id, can be first parameter or second only in combination with userId" + "description": "Device id, can be first parameter or second only in combination with userId" }, "groupId": { "type": "integer", - "description": "Group Id, can be first parameter or second only in combination with userId" + "description": "Group id, can be first parameter or second only in combination with userId" }, "geofenceId": { "type": "integer", - "description": "Geofence Id, can be second parameter only" + "description": "Geofence id, can be second parameter only" }, "notificationId": { "type": "integer", - "description": "Notification Id, can be second parameter only" + "description": "Notification id, can be second parameter only" }, "calendarId": { "type": "integer", - "description": "Calendar Id, can be second parameter only and only in combination with userId" + "description": "Calendar id, can be second parameter only and only in combination with userId" }, "attributeId": { "type": "integer", - "description": "Computed Attribute Id, can be second parameter only" + "description": "Computed attribute id, can be second parameter only" }, "driverId": { "type": "integer", - "description": "Driver Id, can be second parameter only" + "description": "Driver id, can be second parameter only" }, "managedUserId": { "type": "integer", - "description": "User Id, can be second parameter only and only in combination with userId" + "description": "User id, can be second parameter only and only in combination with userId" + }, + "commandId": { + "type": "integer", + "description": "Saved command id, can be second parameter only" } }, "description": "This is a permission map that contain two object indexes. It is used to link/unlink objects. Order is important. Example: { deviceId:8, geofenceId: 16 }" -- cgit v1.2.3 From 3a5edf787fc4dc3fdb7caa30602dee1e5fab8157 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 6 Aug 2023 07:41:21 -0700 Subject: Additional CB212-C1005 data --- src/main/java/org/traccar/helper/ObdDecoder.java | 36 ++++++++++++---------- .../traccar/protocol/CastelProtocolDecoder.java | 31 +++++++++++++++++-- .../protocol/CastelProtocolDecoderTest.java | 8 +++++ 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/traccar/helper/ObdDecoder.java b/src/main/java/org/traccar/helper/ObdDecoder.java index b22065f4e..3cbae334a 100644 --- a/src/main/java/org/traccar/helper/ObdDecoder.java +++ b/src/main/java/org/traccar/helper/ObdDecoder.java @@ -51,22 +51,7 @@ public final class ObdDecoder { StringBuilder codes = new StringBuilder(); for (int i = 0; i < value.length() / 4; i++) { int numValue = Integer.parseInt(value.substring(i * 4, (i + 1) * 4), 16); - codes.append(' '); - switch (numValue >> 14) { - case 1: - codes.append('C'); - break; - case 2: - codes.append('B'); - break; - case 3: - codes.append('U'); - break; - default: - codes.append('P'); - break; - } - codes.append(String.format("%04X", numValue & 0x3FFF)); + codes.append(' ').append(decodeCode(numValue)); } if (codes.length() > 0) { return createEntry(Position.KEY_DTCS, codes.toString().trim()); @@ -75,6 +60,25 @@ public final class ObdDecoder { } } + public static String decodeCode(int value) { + char prefix; + switch (value >> 14) { + case 1: + prefix = 'C'; + break; + case 2: + prefix = 'B'; + break; + case 3: + prefix = 'U'; + break; + default: + prefix = 'P'; + break; + } + return String.format("%c%04X", prefix, value & 0x3FFF); + } + public static Map.Entry decodeData(int pid, long value, boolean convert) { switch (pid) { case 0x04: diff --git a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java index 4aa65245b..4d56e40c9 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java @@ -284,15 +284,27 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { case 0x0C: position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); break; + case 0x0D: + position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING); + break; case 0x0E: position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); break; + case 0x11: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + case 0x12: + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + break; case 0x16: position.set(Position.KEY_IGNITION, true); break; case 0x17: position.set(Position.KEY_IGNITION, false); break; + case 0x1C: + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + break; default: break; } @@ -359,9 +371,9 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { int alarmCount = buf.readUnsignedByte(); for (int i = 0; i < alarmCount; i++) { if (buf.readUnsignedByte() != 0) { - int alarm = buf.readUnsignedByte(); + int event = buf.readUnsignedByte(); for (Position p : positions) { - decodeAlarm(p, alarm); + decodeAlarm(p, event); } buf.readUnsignedShortLE(); // description buf.readUnsignedShortLE(); // threshold @@ -421,12 +433,25 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { return position; case MSG_SC_DTCS_PASSENGER: + case MSG_SC_DTCS_COMMERCIAL: position = createPosition(deviceSession); decodeStat(position, buf); buf.readUnsignedByte(); // flag - position.add(ObdDecoder.decodeCodes(ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())))); + + count = buf.readUnsignedByte(); + StringBuilder codes = new StringBuilder(); + for (int i = 0; i < count; i++) { + if (type == MSG_SC_DTCS_COMMERCIAL) { + codes.append(ObdDecoder.decodeCode(buf.readUnsignedShortLE())); + buf.readUnsignedByte(); // attribute + buf.readUnsignedByte(); // occurrence + } else { + codes.append(ObdDecoder.decodeCode(buf.readUnsignedShortLE())); + } + } + position.set(Position.KEY_DTCS, codes.toString().trim()); return position; diff --git a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java index e9cbac5ce..52c6a86a6 100644 --- a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java @@ -11,6 +11,14 @@ public class CastelProtocolDecoderTest extends ProtocolTest { var decoder = inject(new CastelProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "40404700043231335732303139303033353400000000000000400BBE723A5DEF723A5D000000000000000000000000000000000000030100011900030001012603030145C90D0A"), + Position.KEY_DTCS, "P0326"); + + verifyAttribute(decoder, binary( + "40404500033231334c323031373030303432320000000000004006e1ad205bf1ad205b48510f000000000050160000000000020400053f007c000083040001511346160d0a"), + Position.KEY_DTCS, "P1351"); + verifyAttribute(decoder, binary( "40403a00043231334744503230313830323133343300000000a002000001000001012011004d414c43333831434d4b4d353637313438c8fc0d0a"), Position.KEY_RESULT, "MALC381CMKM567148"); -- cgit v1.2.3 From 36d319a81dc3d2c12222cce012c1a1a307a865b2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 6 Aug 2023 07:45:59 -0700 Subject: Remove unused import --- src/main/java/org/traccar/protocol/CastelProtocolDecoder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java index 4d56e40c9..566d856bb 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java @@ -16,7 +16,6 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -- cgit v1.2.3 From f0799e255a582a61ca9de1eb715af8b9849cc81a Mon Sep 17 00:00:00 2001 From: Rodolfo Silva Date: Mon, 7 Aug 2023 10:50:32 -0300 Subject: fix: remove AMQP auto close connection --- src/main/java/org/traccar/forward/AmqpClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/forward/AmqpClient.java b/src/main/java/org/traccar/forward/AmqpClient.java index 302aa664c..361cfffee 100644 --- a/src/main/java/org/traccar/forward/AmqpClient.java +++ b/src/main/java/org/traccar/forward/AmqpClient.java @@ -43,7 +43,8 @@ public class AmqpClient { throw new RuntimeException("Error while setting URI for RabbitMQ connection factory", e); } - try (Connection connection = factory.newConnection()) { + try { + Connection connection = factory.newConnection(); channel = connection.createChannel(); channel.exchangeDeclare(exchange, BuiltinExchangeType.TOPIC, true); } catch (IOException | TimeoutException e) { -- cgit v1.2.3 From ac2ca17894da7fd43432c63056f6abef4a7a611b Mon Sep 17 00:00:00 2001 From: Rodolfo Silva Date: Mon, 7 Aug 2023 12:05:06 -0300 Subject: fix: add shutdown hook to close the AMQP connection --- src/main/java/org/traccar/forward/AmqpClient.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/traccar/forward/AmqpClient.java b/src/main/java/org/traccar/forward/AmqpClient.java index 361cfffee..8ac618f5c 100644 --- a/src/main/java/org/traccar/forward/AmqpClient.java +++ b/src/main/java/org/traccar/forward/AmqpClient.java @@ -47,6 +47,13 @@ public class AmqpClient { Connection connection = factory.newConnection(); channel = connection.createChannel(); channel.exchangeDeclare(exchange, BuiltinExchangeType.TOPIC, true); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + connection.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + })); } catch (IOException | TimeoutException e) { throw new RuntimeException("Error while creating and configuring RabbitMQ channel", e); } -- cgit v1.2.3 From 78ead877bac40cd88fc342e966741b42568de5a5 Mon Sep 17 00:00:00 2001 From: Rodolfo Silva Date: Mon, 7 Aug 2023 16:47:56 -0300 Subject: fix: remove the AmqpClient shutdown hook --- src/main/java/org/traccar/forward/AmqpClient.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/org/traccar/forward/AmqpClient.java b/src/main/java/org/traccar/forward/AmqpClient.java index 8ac618f5c..361cfffee 100644 --- a/src/main/java/org/traccar/forward/AmqpClient.java +++ b/src/main/java/org/traccar/forward/AmqpClient.java @@ -47,13 +47,6 @@ public class AmqpClient { Connection connection = factory.newConnection(); channel = connection.createChannel(); channel.exchangeDeclare(exchange, BuiltinExchangeType.TOPIC, true); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - try { - connection.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - })); } catch (IOException | TimeoutException e) { throw new RuntimeException("Error while creating and configuring RabbitMQ channel", e); } -- cgit v1.2.3 From 867404e9d7ffc6019d8d87dedc892aef1e70aec8 Mon Sep 17 00:00:00 2001 From: seym45 Date: Thu, 10 Aug 2023 01:26:28 +0400 Subject: Add gator commands to manage engine --- src/main/java/org/traccar/protocol/GatorProtocolDecoder.java | 4 +++- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index f7da5dc75..a5ecb2169 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -19,7 +19,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BcdUtil; @@ -27,6 +26,7 @@ import org.traccar.helper.Checksum; import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; +import org.traccar.session.DeviceSession; import java.net.SocketAddress; @@ -38,6 +38,8 @@ 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_RESTORES_THE_OIL_DUCT = 0x38; + public static final int MSG_CLOSE_THE_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..6d96c6e9a 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -69,6 +69,10 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { switch (command.getType()) { case Command.TYPE_POSITION_SINGLE: return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST); + case Command.TYPE_ENGINE_STOP: + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_THE_OIL_DUCT); + case Command.TYPE_ENGINE_RESUME: + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESTORES_THE_OIL_DUCT); default: return null; } -- cgit v1.2.3 From 4157920142182c080dc6a4f21f19417d068fedc5 Mon Sep 17 00:00:00 2001 From: seym45 Date: Thu, 10 Aug 2023 01:46:02 +0400 Subject: Set support for engine management --- src/main/java/org/traccar/protocol/GatorProtocol.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index 46862f583..096095463 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -29,6 +29,8 @@ public class GatorProtocol extends BaseProtocol { @Inject public GatorProtocol(Config config) { setSupportedDataCommands(Command.TYPE_POSITION_SINGLE); + setSupportedDataCommands(Command.TYPE_ENGINE_RESUME); + setSupportedDataCommands(Command.TYPE_ENGINE_STOP); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { -- cgit v1.2.3 From 08a3f9c4530d072a224037eaa8683195c4233f84 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 13 Aug 2023 07:44:29 -0700 Subject: Support SL22 SL24 SL28 devices --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 53c812bb7..56a915e7d 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -916,7 +916,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } } - if (type == MSG_GPS_LBS_7) { + if (buf.readableBytes() == 3 + 6 || buf.readableBytes() == 3 + 4 + 6) { position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); buf.readUnsignedByte(); // upload mode position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0 ? true : null); -- cgit v1.2.3 From 7d53ddabd857330cd9791b12484d925857842cc9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 13 Aug 2023 08:23:40 -0700 Subject: Support SL42 SL44 SL48 devices --- .../org/traccar/protocol/Gt06ProtocolDecoder.java | 43 ++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 56a915e7d..161d04d8d 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -78,11 +78,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_HEARTBEAT = 0x23; // GK310 public static final int MSG_ADDRESS_REQUEST = 0x2A; // GK310 public static final int MSG_ADDRESS_RESPONSE = 0x97; // GK310 - public static final int MSG_GPS_LBS_5 = 0x31; // AZ735 - public static final int MSG_GPS_LBS_STATUS_4 = 0x32; // AZ735 - public static final int MSG_WIFI_5 = 0x33; // AZ735 - public static final int MSG_AZ735_GPS = 0x32; // AZ735 / only extended - public static final int MSG_AZ735_ALARM = 0x33; // AZ735 / only extended + public static final int MSG_GPS_LBS_5 = 0x31; // AZ735 & SL4X + public static final int MSG_GPS_LBS_STATUS_4 = 0x32; // AZ735 & SL4X + public static final int MSG_WIFI_5 = 0x33; // AZ735 & SL4X + public static final int MSG_LBS_3 = 0x34; // SL4X + public static final int MSG_AZ735_GPS = 0x32; // AZ735 (extended) + public static final int MSG_AZ735_ALARM = 0x33; // AZ735 (only extended) public static final int MSG_X1_GPS = 0x34; public static final int MSG_X1_PHOTO_INFO = 0x35; public static final int MSG_X1_PHOTO_DATA = 0x36; @@ -122,6 +123,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { OBD6, WETRUST, JC400, + SL4X, } private Variant variant; @@ -549,7 +551,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return null; - } else if (type == MSG_X1_GPS) { + } else if (type == MSG_X1_GPS && variant != Variant.SL4X) { buf.readUnsignedInt(); // data and alarm @@ -682,41 +684,50 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return position; } else if (type == MSG_LBS_MULTIPLE_1 || type == MSG_LBS_MULTIPLE_2 || type == MSG_LBS_MULTIPLE_3 - || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI || type == MSG_LBS_2 + || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI || type == MSG_LBS_2 || type == MSG_LBS_3 || type == MSG_WIFI_3 || type == MSG_WIFI_5) { - boolean longFormat = type == MSG_LBS_2 || type == MSG_WIFI_3 || type == MSG_WIFI_5; - DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE)) .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); getLastLocation(position, dateBuilder.getDate()); - if (variant == Variant.WANWAY_S20) { + if (variant == Variant.WANWAY_S20 || variant == Variant.SL4X) { buf.readUnsignedByte(); // ta } int mcc = buf.readUnsignedShort(); - int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); + int mnc = BitUtil.check(mcc, 15) || variant == Variant.SL4X + ? buf.readUnsignedShort() : buf.readUnsignedByte(); Network network = new Network(); int cellCount = variant == Variant.WANWAY_S20 ? buf.readUnsignedByte() : type == MSG_WIFI_5 ? 6 : 7; for (int i = 0; i < cellCount; i++) { - int lac = longFormat ? buf.readInt() : buf.readUnsignedShort(); - int cid = longFormat ? (int) buf.readLong() : buf.readUnsignedMedium(); + int lac; + int cid; + if (type == MSG_LBS_2 || type == MSG_WIFI_3) { + lac = buf.readInt(); + cid = (int) buf.readLong(); + } else if (type == MSG_WIFI_5 || type == MSG_LBS_3) { + lac = buf.readUnsignedShort(); + cid = (int) buf.readUnsignedInt(); + } else { + lac = buf.readUnsignedShort(); + cid = buf.readUnsignedMedium(); + } int rssi = -buf.readUnsignedByte(); if (lac > 0) { network.addCellTower(CellTower.from(BitUtil.to(mcc, 15), mnc, lac, cid, rssi)); } } - if (variant != Variant.WANWAY_S20) { + if (variant != Variant.WANWAY_S20 && variant != Variant.SL4X) { buf.readUnsignedByte(); // ta } if (type != MSG_LBS_MULTIPLE_1 && type != MSG_LBS_MULTIPLE_2 && type != MSG_LBS_MULTIPLE_3 - && type != MSG_LBS_2) { + && type != MSG_LBS_2 && type != MSG_LBS_3) { int wifiCount = buf.readUnsignedByte(); for (int i = 0; i < wifiCount; i++) { String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); @@ -1455,6 +1466,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.WETRUST; } else if (header == 0x7878 && type == MSG_ALARM && buf.getUnsignedShort(buf.readerIndex() + 4) == 0xffff) { variant = Variant.JC400; + } else if (header == 0x7878 && type == MSG_LBS_3 && length == 0x37) { + variant = Variant.SL4X; } else { variant = Variant.STANDARD; } -- cgit v1.2.3 From 25c8da353ead804eabb5b3388f711f20585feff3 Mon Sep 17 00:00:00 2001 From: Jamie Guthrie Date: Tue, 15 Aug 2023 12:45:46 +0200 Subject: Throw overspeed event immediately, accounting for minimumDuration --- .../traccar/session/state/OverspeedProcessor.java | 37 ++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/traccar/session/state/OverspeedProcessor.java b/src/main/java/org/traccar/session/state/OverspeedProcessor.java index 62f6a3de2..a6cd72322 100644 --- a/src/main/java/org/traccar/session/state/OverspeedProcessor.java +++ b/src/main/java/org/traccar/session/state/OverspeedProcessor.java @@ -34,22 +34,7 @@ public final class OverspeedProcessor { if (oldState) { boolean newState = position.getSpeed() > speedLimit; if (newState) { - if (state.getOverspeedTime() != null) { - long oldTime = state.getOverspeedTime().getTime(); - long newTime = position.getFixTime().getTime(); - if (newTime - oldTime > minimalDuration) { - - Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position); - event.set(ATTRIBUTE_SPEED, position.getSpeed()); - event.set(Position.KEY_SPEED_LIMIT, speedLimit); - event.setGeofenceId(state.getOverspeedGeofenceId()); - - state.setOverspeedTime(null); - state.setOverspeedGeofenceId(0); - state.setEvent(event); - - } - } + setEvent(state, position, speedLimit, minimalDuration); } else { state.setOverspeedState(false); state.setOverspeedTime(null); @@ -59,7 +44,27 @@ public final class OverspeedProcessor { state.setOverspeedState(true); state.setOverspeedTime(position.getFixTime()); state.setOverspeedGeofenceId(geofenceId); + + setEvent(state, position, speedLimit, minimalDuration); } } + private static void setEvent(OverspeedState state, Position position, double speedLimit, long minimalDuration) { + if (state.getOverspeedTime() != null) { + long oldTime = state.getOverspeedTime().getTime(); + long newTime = position.getFixTime().getTime(); + if (newTime - oldTime >= minimalDuration) { + + Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position); + event.set(ATTRIBUTE_SPEED, position.getSpeed()); + event.set(Position.KEY_SPEED_LIMIT, speedLimit); + event.setGeofenceId(state.getOverspeedGeofenceId()); + + state.setOverspeedTime(null); + state.setOverspeedGeofenceId(0); + state.setEvent(event); + + } + } + } } -- cgit v1.2.3 From 95059cb3db832a26c6dbf3706aded3a2ffbcf3d8 Mon Sep 17 00:00:00 2001 From: Jamie Guthrie Date: Tue, 15 Aug 2023 21:20:21 +0200 Subject: Rename setEvent method to checkEvent --- src/main/java/org/traccar/session/state/OverspeedProcessor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/session/state/OverspeedProcessor.java b/src/main/java/org/traccar/session/state/OverspeedProcessor.java index a6cd72322..b23649570 100644 --- a/src/main/java/org/traccar/session/state/OverspeedProcessor.java +++ b/src/main/java/org/traccar/session/state/OverspeedProcessor.java @@ -34,7 +34,7 @@ public final class OverspeedProcessor { if (oldState) { boolean newState = position.getSpeed() > speedLimit; if (newState) { - setEvent(state, position, speedLimit, minimalDuration); + checkEvent(state, position, speedLimit, minimalDuration); } else { state.setOverspeedState(false); state.setOverspeedTime(null); @@ -45,11 +45,11 @@ public final class OverspeedProcessor { state.setOverspeedTime(position.getFixTime()); state.setOverspeedGeofenceId(geofenceId); - setEvent(state, position, speedLimit, minimalDuration); + checkEvent(state, position, speedLimit, minimalDuration); } } - private static void setEvent(OverspeedState state, Position position, double speedLimit, long minimalDuration) { + private static void checkEvent(OverspeedState state, Position position, double speedLimit, long minimalDuration) { if (state.getOverspeedTime() != null) { long oldTime = state.getOverspeedTime().getTime(); long newTime = position.getFixTime().getTime(); -- cgit v1.2.3 From a1c12c50a8d0023d6ccfbf4eb0723a90eab55cc5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 17 Aug 2023 06:56:58 -0700 Subject: Disable for UDP protocols --- src/main/java/org/traccar/BasePipelineFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index d04fed383..5b48f3d15 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -125,7 +125,7 @@ public abstract class BasePipelineFactory extends ChannelInitializer { } pipeline.addLast(new NetworkMessageHandler()); pipeline.addLast(new StandardLoggingHandler(protocol)); - if (!config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) { + if (!connector.isDatagram() && !config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) { pipeline.addLast(new AcknowledgementHandler()); } -- cgit v1.2.3 From 51712e33c363d5150cfd690d6f3c466a38ab6ba3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 19 Aug 2023 10:32:35 -0700 Subject: Support statistics attributes --- src/main/java/org/traccar/database/StatisticsManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index e417c8901..0e9931fba 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -100,6 +100,8 @@ public class StatisticsManager { statistics.setProtocols(protocols); } + statistics.set("modern", config.getString(Keys.WEB_PATH).contains("modern")); + users.clear(); deviceProtocols.clear(); deviceMessages.clear(); @@ -141,6 +143,13 @@ public class StatisticsManager { LOGGER.warn("Failed to serialize protocols", e); } } + if (!statistics.getAttributes().isEmpty()) { + try { + form.param("attributes", objectMapper.writeValueAsString(statistics.getAttributes())); + } catch (JsonProcessingException e) { + LOGGER.warn("Failed to serialize attributes", e); + } + } client.target(url).request().async().post(Entity.form(form)); } -- cgit v1.2.3 From 9df5d93ba0482b628d05b10c29100144beed5b5d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 19 Aug 2023 13:25:39 -0700 Subject: Move from javax to jakarta --- build.gradle | 50 +++++++++++----------- src/main/java/org/traccar/BaseProtocol.java | 4 +- src/main/java/org/traccar/BaseProtocolDecoder.java | 2 +- src/main/java/org/traccar/BaseProtocolEncoder.java | 2 +- .../java/org/traccar/ExtendedObjectDecoder.java | 2 +- src/main/java/org/traccar/MainEventHandler.java | 4 +- src/main/java/org/traccar/MainModule.java | 12 +++--- .../org/traccar/PositionForwardingHandler.java | 6 +-- src/main/java/org/traccar/ServerManager.java | 4 +- .../java/org/traccar/api/AsyncSocketServlet.java | 6 +-- .../java/org/traccar/api/BaseObjectResource.java | 16 +++---- src/main/java/org/traccar/api/BaseResource.java | 6 +-- .../java/org/traccar/api/CorsResponseFilter.java | 10 ++--- .../api/DateParameterConverterProvider.java | 4 +- .../org/traccar/api/ExtendedObjectResource.java | 4 +- src/main/java/org/traccar/api/MediaFilter.java | 20 ++++----- .../java/org/traccar/api/ResourceErrorHandler.java | 6 +-- .../java/org/traccar/api/SimpleObjectResource.java | 4 +- .../traccar/api/resource/AttributeResource.java | 22 +++++----- .../org/traccar/api/resource/CalendarResource.java | 8 ++-- .../org/traccar/api/resource/CommandResource.java | 18 ++++---- .../org/traccar/api/resource/DeviceResource.java | 26 +++++------ .../org/traccar/api/resource/DriverResource.java | 8 ++-- .../org/traccar/api/resource/EventResource.java | 16 +++---- .../org/traccar/api/resource/GeofenceResource.java | 8 ++-- .../org/traccar/api/resource/GroupResource.java | 8 ++-- .../traccar/api/resource/MaintenanceResource.java | 8 ++-- .../traccar/api/resource/NotificationResource.java | 18 ++++---- .../org/traccar/api/resource/OrderResource.java | 8 ++-- .../org/traccar/api/resource/PasswordResource.java | 20 ++++----- .../traccar/api/resource/PermissionsResource.java | 18 ++++---- .../org/traccar/api/resource/PositionResource.java | 24 +++++------ .../org/traccar/api/resource/ReportResource.java | 24 +++++------ .../org/traccar/api/resource/ServerResource.java | 26 +++++------ .../org/traccar/api/resource/SessionResource.java | 36 ++++++++-------- .../traccar/api/resource/StatisticsResource.java | 12 +++--- .../org/traccar/api/resource/UserResource.java | 20 ++++----- .../org/traccar/api/security/LoginService.java | 6 +-- .../traccar/api/security/PermissionsService.java | 2 +- .../api/security/SecurityRequestFilter.java | 20 ++++----- .../traccar/api/security/UserSecurityContext.java | 2 +- .../org/traccar/api/signature/CryptoManager.java | 4 +- .../org/traccar/api/signature/TokenManager.java | 4 +- src/main/java/org/traccar/config/Config.java | 4 +- .../java/org/traccar/database/CommandsManager.java | 6 +-- .../org/traccar/database/DeviceLookupService.java | 4 +- .../java/org/traccar/database/MediaManager.java | 4 +- .../org/traccar/database/NotificationManager.java | 6 +-- .../java/org/traccar/database/OpenIdProvider.java | 2 +- .../org/traccar/database/StatisticsManager.java | 10 ++--- .../org/traccar/forward/EventForwarderJson.java | 8 ++-- .../java/org/traccar/forward/NetworkForwarder.java | 4 +- .../org/traccar/forward/PositionForwarderJson.java | 12 +++--- .../org/traccar/forward/PositionForwarderUrl.java | 6 +-- .../java/org/traccar/geocoder/BanGeocoder.java | 6 +-- .../org/traccar/geocoder/BingMapsGeocoder.java | 6 +-- .../java/org/traccar/geocoder/FactualGeocoder.java | 4 +- .../org/traccar/geocoder/GeoapifyGeocoder.java | 6 +-- .../org/traccar/geocoder/GeocodeFarmGeocoder.java | 4 +- .../org/traccar/geocoder/GeocodeXyzGeocoder.java | 4 +- .../org/traccar/geocoder/GisgraphyGeocoder.java | 4 +- .../java/org/traccar/geocoder/GoogleGeocoder.java | 8 ++-- .../java/org/traccar/geocoder/HereGeocoder.java | 4 +- .../java/org/traccar/geocoder/JsonGeocoder.java | 8 ++-- .../org/traccar/geocoder/LocationIqGeocoder.java | 2 +- .../org/traccar/geocoder/MapQuestGeocoder.java | 6 +-- .../org/traccar/geocoder/MapTilerGeocoder.java | 6 +-- .../java/org/traccar/geocoder/MapboxGeocoder.java | 8 ++-- .../org/traccar/geocoder/MapmyIndiaGeocoder.java | 6 +-- .../org/traccar/geocoder/NominatimGeocoder.java | 4 +- .../org/traccar/geocoder/OpenCageGeocoder.java | 6 +-- .../traccar/geocoder/PositionStackGeocoder.java | 6 +-- .../java/org/traccar/geocoder/TomTomGeocoder.java | 6 +-- .../geolocation/GoogleGeolocationProvider.java | 2 +- .../geolocation/MozillaGeolocationProvider.java | 2 +- .../geolocation/OpenCellIdGeolocationProvider.java | 6 +-- .../geolocation/UniversalGeolocationProvider.java | 8 ++-- .../geolocation/UnwiredGeolocationProvider.java | 8 ++-- .../traccar/handler/ComputedAttributesHandler.java | 4 +- .../org/traccar/handler/CopyAttributesHandler.java | 4 +- .../org/traccar/handler/DefaultDataHandler.java | 4 +- .../java/org/traccar/handler/DistanceHandler.java | 4 +- .../org/traccar/handler/EngineHoursHandler.java | 4 +- .../java/org/traccar/handler/FilterHandler.java | 4 +- .../java/org/traccar/handler/GeofenceHandler.java | 4 +- .../org/traccar/handler/HemisphereHandler.java | 4 +- .../java/org/traccar/handler/MotionHandler.java | 4 +- .../traccar/handler/NetworkForwarderHandler.java | 2 +- .../org/traccar/handler/RemoteAddressHandler.java | 4 +- .../org/traccar/handler/SpeedLimitHandler.java | 4 +- src/main/java/org/traccar/handler/TimeHandler.java | 4 +- .../traccar/handler/events/AlertEventHandler.java | 4 +- .../traccar/handler/events/BaseEventHandler.java | 2 +- .../handler/events/BehaviorEventHandler.java | 4 +- .../handler/events/CommandResultEventHandler.java | 4 +- .../traccar/handler/events/DriverEventHandler.java | 4 +- .../traccar/handler/events/FuelEventHandler.java | 4 +- .../handler/events/GeofenceEventHandler.java | 4 +- .../handler/events/IgnitionEventHandler.java | 4 +- .../handler/events/MaintenanceEventHandler.java | 4 +- .../traccar/handler/events/MediaEventHandler.java | 4 +- .../traccar/handler/events/MotionEventHandler.java | 4 +- .../handler/events/OverspeedEventHandler.java | 4 +- .../helper/ObjectMapperContextResolver.java | 4 +- src/main/java/org/traccar/helper/WebHelper.java | 2 +- src/main/java/org/traccar/mail/LogMailManager.java | 4 +- src/main/java/org/traccar/mail/MailManager.java | 4 +- .../java/org/traccar/mail/SmtpMailManager.java | 20 ++++----- .../notification/NotificationFormatter.java | 4 +- .../traccar/notification/NotificatorManager.java | 4 +- .../notification/TextTemplateFormatter.java | 4 +- .../traccar/notificators/NotificatorCommand.java | 4 +- .../traccar/notificators/NotificatorFirebase.java | 4 +- .../org/traccar/notificators/NotificatorMail.java | 6 +-- .../traccar/notificators/NotificatorPushover.java | 8 ++-- .../org/traccar/notificators/NotificatorSms.java | 4 +- .../traccar/notificators/NotificatorTelegram.java | 8 ++-- .../traccar/notificators/NotificatorTraccar.java | 12 +++--- .../org/traccar/notificators/NotificatorWeb.java | 4 +- .../java/org/traccar/protocol/AdmProtocol.java | 2 +- .../java/org/traccar/protocol/AisProtocol.java | 2 +- .../org/traccar/protocol/AlematicsProtocol.java | 2 +- .../java/org/traccar/protocol/AnytrekProtocol.java | 2 +- .../java/org/traccar/protocol/ApelProtocol.java | 2 +- .../java/org/traccar/protocol/AplicomProtocol.java | 2 +- .../java/org/traccar/protocol/AppelloProtocol.java | 2 +- .../java/org/traccar/protocol/AquilaProtocol.java | 2 +- .../java/org/traccar/protocol/Ardi01Protocol.java | 2 +- .../java/org/traccar/protocol/ArknavProtocol.java | 2 +- .../org/traccar/protocol/ArknavX8Protocol.java | 2 +- .../java/org/traccar/protocol/ArmoliProtocol.java | 2 +- .../java/org/traccar/protocol/ArnaviProtocol.java | 2 +- .../traccar/protocol/ArnaviProtocolDecoder.java | 2 +- .../java/org/traccar/protocol/AstraProtocol.java | 2 +- .../java/org/traccar/protocol/At2000Protocol.java | 2 +- .../java/org/traccar/protocol/AtrackProtocol.java | 2 +- .../java/org/traccar/protocol/AuroProtocol.java | 2 +- .../org/traccar/protocol/AustinNbProtocol.java | 2 +- .../java/org/traccar/protocol/AutoFonProtocol.java | 2 +- .../org/traccar/protocol/AutoGradeProtocol.java | 2 +- .../org/traccar/protocol/AutoTrackProtocol.java | 2 +- .../java/org/traccar/protocol/AvemaProtocol.java | 2 +- .../java/org/traccar/protocol/Avl301Protocol.java | 2 +- .../java/org/traccar/protocol/B2316Protocol.java | 2 +- .../org/traccar/protocol/B2316ProtocolDecoder.java | 6 +-- .../java/org/traccar/protocol/BceProtocol.java | 2 +- .../org/traccar/protocol/BlackKiteProtocol.java | 2 +- .../java/org/traccar/protocol/BlueProtocol.java | 2 +- .../java/org/traccar/protocol/BoxProtocol.java | 2 +- .../java/org/traccar/protocol/BstplProtocol.java | 2 +- .../java/org/traccar/protocol/C2stekProtocol.java | 2 +- .../java/org/traccar/protocol/CalAmpProtocol.java | 2 +- .../org/traccar/protocol/CarTrackProtocol.java | 2 +- .../java/org/traccar/protocol/CarcellProtocol.java | 2 +- .../java/org/traccar/protocol/CarscopProtocol.java | 2 +- .../java/org/traccar/protocol/CastelProtocol.java | 2 +- .../java/org/traccar/protocol/CautelaProtocol.java | 2 +- .../org/traccar/protocol/CellocatorProtocol.java | 2 +- .../java/org/traccar/protocol/CguardProtocol.java | 2 +- .../org/traccar/protocol/CityeasyProtocol.java | 2 +- .../org/traccar/protocol/ContinentalProtocol.java | 2 +- .../org/traccar/protocol/CradlepointProtocol.java | 2 +- .../java/org/traccar/protocol/DingtekProtocol.java | 2 +- .../java/org/traccar/protocol/DishaProtocol.java | 2 +- .../java/org/traccar/protocol/DmtHttpProtocol.java | 2 +- .../traccar/protocol/DmtHttpProtocolDecoder.java | 6 +-- .../java/org/traccar/protocol/DmtProtocol.java | 2 +- .../java/org/traccar/protocol/DolphinProtocol.java | 2 +- .../java/org/traccar/protocol/Dsf22Protocol.java | 2 +- .../java/org/traccar/protocol/DualcamProtocol.java | 2 +- .../java/org/traccar/protocol/DwayProtocol.java | 2 +- .../org/traccar/protocol/EasyTrackProtocol.java | 2 +- .../java/org/traccar/protocol/EelinkProtocol.java | 2 +- .../java/org/traccar/protocol/EgtsProtocol.java | 2 +- .../java/org/traccar/protocol/EnforaProtocol.java | 2 +- .../java/org/traccar/protocol/EnnfuProtocol.java | 2 +- .../org/traccar/protocol/EnvotechProtocol.java | 2 +- .../java/org/traccar/protocol/EsealProtocol.java | 2 +- .../java/org/traccar/protocol/EskyProtocol.java | 2 +- .../org/traccar/protocol/ExtremTracProtocol.java | 2 +- .../org/traccar/protocol/FifotrackProtocol.java | 2 +- .../java/org/traccar/protocol/FlespiProtocol.java | 2 +- .../traccar/protocol/FlespiProtocolDecoder.java | 12 +++--- .../java/org/traccar/protocol/FlexApiProtocol.java | 2 +- .../traccar/protocol/FlexApiProtocolDecoder.java | 4 +- .../org/traccar/protocol/FlexCommProtocol.java | 2 +- .../traccar/protocol/FlexibleReportProtocol.java | 2 +- .../org/traccar/protocol/FlextrackProtocol.java | 2 +- .../java/org/traccar/protocol/FoxProtocol.java | 2 +- .../java/org/traccar/protocol/FreedomProtocol.java | 2 +- .../org/traccar/protocol/FreematicsProtocol.java | 2 +- .../org/traccar/protocol/FutureWayProtocol.java | 2 +- .../java/org/traccar/protocol/G1rusProtocol.java | 2 +- .../java/org/traccar/protocol/GalileoProtocol.java | 2 +- .../java/org/traccar/protocol/GatorProtocol.java | 2 +- .../java/org/traccar/protocol/GenxProtocol.java | 2 +- .../java/org/traccar/protocol/Gl100Protocol.java | 2 +- .../java/org/traccar/protocol/Gl200Protocol.java | 2 +- .../org/traccar/protocol/Gl200ProtocolDecoder.java | 2 +- .../org/traccar/protocol/GlobalSatProtocol.java | 2 +- .../org/traccar/protocol/GlobalstarProtocol.java | 2 +- .../java/org/traccar/protocol/GnxProtocol.java | 2 +- .../java/org/traccar/protocol/GoSafeProtocol.java | 2 +- .../java/org/traccar/protocol/GotopProtocol.java | 2 +- .../java/org/traccar/protocol/Gps056Protocol.java | 2 +- .../java/org/traccar/protocol/Gps103Protocol.java | 2 +- .../java/org/traccar/protocol/GpsGateProtocol.java | 2 +- .../org/traccar/protocol/GpsMarkerProtocol.java | 2 +- .../java/org/traccar/protocol/GpsmtaProtocol.java | 2 +- .../java/org/traccar/protocol/GranitProtocol.java | 2 +- .../java/org/traccar/protocol/Gs100Protocol.java | 2 +- .../java/org/traccar/protocol/Gt02Protocol.java | 2 +- .../java/org/traccar/protocol/Gt06Protocol.java | 2 +- .../java/org/traccar/protocol/Gt30Protocol.java | 2 +- .../java/org/traccar/protocol/H02Protocol.java | 2 +- .../java/org/traccar/protocol/HaicomProtocol.java | 2 +- .../java/org/traccar/protocol/HomtecsProtocol.java | 2 +- .../java/org/traccar/protocol/HoopoProtocol.java | 2 +- .../org/traccar/protocol/HoopoProtocolDecoder.java | 4 +- .../org/traccar/protocol/HuaShengProtocol.java | 2 +- .../java/org/traccar/protocol/HuabaoProtocol.java | 2 +- .../org/traccar/protocol/HunterProProtocol.java | 2 +- .../java/org/traccar/protocol/IdplProtocol.java | 2 +- .../org/traccar/protocol/IntellitracProtocol.java | 2 +- .../java/org/traccar/protocol/IotmProtocol.java | 2 +- .../java/org/traccar/protocol/ItsProtocol.java | 2 +- .../java/org/traccar/protocol/Ivt401Protocol.java | 2 +- .../java/org/traccar/protocol/JidoProtocol.java | 2 +- .../org/traccar/protocol/JpKorjarProtocol.java | 2 +- .../java/org/traccar/protocol/Jt600Protocol.java | 2 +- .../java/org/traccar/protocol/KenjiProtocol.java | 2 +- .../java/org/traccar/protocol/KhdProtocol.java | 2 +- .../java/org/traccar/protocol/L100Protocol.java | 2 +- .../java/org/traccar/protocol/LacakProtocol.java | 2 +- .../org/traccar/protocol/LacakProtocolDecoder.java | 4 +- .../java/org/traccar/protocol/LaipacProtocol.java | 2 +- .../java/org/traccar/protocol/LeafSpyProtocol.java | 2 +- .../java/org/traccar/protocol/M2cProtocol.java | 2 +- .../java/org/traccar/protocol/M2mProtocol.java | 2 +- .../java/org/traccar/protocol/MaestroProtocol.java | 2 +- .../org/traccar/protocol/ManPowerProtocol.java | 2 +- .../org/traccar/protocol/Mavlink2Protocol.java | 2 +- .../org/traccar/protocol/MegastekProtocol.java | 2 +- .../org/traccar/protocol/MeiligaoProtocol.java | 2 +- .../org/traccar/protocol/MeitrackProtocol.java | 2 +- .../org/traccar/protocol/MictrackProtocol.java | 2 +- .../org/traccar/protocol/MilesmateProtocol.java | 2 +- .../org/traccar/protocol/MiniFinderProtocol.java | 2 +- .../org/traccar/protocol/Minifinder2Protocol.java | 2 +- .../org/traccar/protocol/MobilogixProtocol.java | 2 +- .../java/org/traccar/protocol/MoovboxProtocol.java | 2 +- .../java/org/traccar/protocol/MotorProtocol.java | 2 +- .../java/org/traccar/protocol/Mta6Protocol.java | 2 +- .../java/org/traccar/protocol/MtxProtocol.java | 2 +- .../java/org/traccar/protocol/MxtProtocol.java | 2 +- .../java/org/traccar/protocol/NavigilProtocol.java | 2 +- .../java/org/traccar/protocol/NavisProtocol.java | 2 +- .../java/org/traccar/protocol/NavisetProtocol.java | 2 +- .../org/traccar/protocol/NavtelecomProtocol.java | 2 +- .../java/org/traccar/protocol/NdtpV6Protocol.java | 2 +- .../java/org/traccar/protocol/NeosProtocol.java | 2 +- .../java/org/traccar/protocol/NetProtocol.java | 2 +- .../java/org/traccar/protocol/NiotProtocol.java | 2 +- .../java/org/traccar/protocol/NoranProtocol.java | 2 +- .../java/org/traccar/protocol/NvsProtocol.java | 2 +- .../java/org/traccar/protocol/NyitechProtocol.java | 2 +- .../org/traccar/protocol/ObdDongleProtocol.java | 2 +- .../java/org/traccar/protocol/OigoProtocol.java | 2 +- .../java/org/traccar/protocol/OkoProtocol.java | 2 +- .../org/traccar/protocol/OmnicommProtocol.java | 2 +- .../java/org/traccar/protocol/OpenGtsProtocol.java | 2 +- .../java/org/traccar/protocol/OrbcommProtocol.java | 2 +- .../traccar/protocol/OrbcommProtocolDecoder.java | 8 ++-- .../java/org/traccar/protocol/OrionProtocol.java | 2 +- .../java/org/traccar/protocol/OsmAndProtocol.java | 2 +- .../java/org/traccar/protocol/OutsafeProtocol.java | 2 +- .../traccar/protocol/OutsafeProtocolDecoder.java | 10 ++--- .../org/traccar/protocol/OwnTracksProtocol.java | 2 +- .../traccar/protocol/OwnTracksProtocolDecoder.java | 4 +- .../org/traccar/protocol/PacificTrackProtocol.java | 2 +- .../org/traccar/protocol/PathAwayProtocol.java | 2 +- .../org/traccar/protocol/PiligrimProtocol.java | 2 +- .../java/org/traccar/protocol/PluginProtocol.java | 2 +- .../java/org/traccar/protocol/PolteProtocol.java | 2 +- .../org/traccar/protocol/PolteProtocolDecoder.java | 4 +- .../java/org/traccar/protocol/PortmanProtocol.java | 2 +- .../org/traccar/protocol/PretraceProtocol.java | 2 +- .../java/org/traccar/protocol/PricolProtocol.java | 2 +- .../org/traccar/protocol/ProgressProtocol.java | 2 +- .../java/org/traccar/protocol/PstProtocol.java | 2 +- .../java/org/traccar/protocol/Pt215Protocol.java | 2 +- .../java/org/traccar/protocol/Pt3000Protocol.java | 2 +- .../java/org/traccar/protocol/Pt502Protocol.java | 2 +- .../java/org/traccar/protocol/Pt60Protocol.java | 2 +- .../java/org/traccar/protocol/R12wProtocol.java | 2 +- .../org/traccar/protocol/RaceDynamicsProtocol.java | 2 +- .../java/org/traccar/protocol/RadarProtocol.java | 2 +- .../java/org/traccar/protocol/RaveonProtocol.java | 2 +- .../java/org/traccar/protocol/RecodaProtocol.java | 2 +- .../org/traccar/protocol/RetranslatorProtocol.java | 2 +- .../java/org/traccar/protocol/RfTrackProtocol.java | 2 +- .../traccar/protocol/RfTrackProtocolDecoder.java | 6 +-- .../java/org/traccar/protocol/RitiProtocol.java | 2 +- .../org/traccar/protocol/RoboTrackProtocol.java | 2 +- .../java/org/traccar/protocol/RstProtocol.java | 2 +- .../java/org/traccar/protocol/RuptelaProtocol.java | 2 +- .../java/org/traccar/protocol/S168Protocol.java | 2 +- .../org/traccar/protocol/SabertekProtocol.java | 2 +- .../java/org/traccar/protocol/SanavProtocol.java | 2 +- .../java/org/traccar/protocol/SanulProtocol.java | 2 +- .../java/org/traccar/protocol/SatsolProtocol.java | 2 +- .../java/org/traccar/protocol/SigfoxProtocol.java | 2 +- .../traccar/protocol/SigfoxProtocolDecoder.java | 10 ++--- .../java/org/traccar/protocol/SiwiProtocol.java | 2 +- .../org/traccar/protocol/SkypatrolProtocol.java | 2 +- .../org/traccar/protocol/SmartSoleProtocol.java | 2 +- .../java/org/traccar/protocol/SmokeyProtocol.java | 2 +- .../org/traccar/protocol/SolarPoweredProtocol.java | 2 +- .../java/org/traccar/protocol/SpotProtocol.java | 2 +- .../org/traccar/protocol/StarLinkProtocol.java | 2 +- .../java/org/traccar/protocol/StarcomProtocol.java | 2 +- .../java/org/traccar/protocol/StartekProtocol.java | 2 +- .../java/org/traccar/protocol/StbProtocol.java | 2 +- .../org/traccar/protocol/StbProtocolDecoder.java | 6 +-- .../java/org/traccar/protocol/Stl060Protocol.java | 2 +- .../java/org/traccar/protocol/SuntechProtocol.java | 2 +- .../org/traccar/protocol/SupermateProtocol.java | 2 +- .../java/org/traccar/protocol/SviasProtocol.java | 2 +- .../org/traccar/protocol/SwiftechProtocol.java | 2 +- .../java/org/traccar/protocol/T55Protocol.java | 2 +- .../java/org/traccar/protocol/T57Protocol.java | 2 +- .../org/traccar/protocol/T622IridiumProtocol.java | 2 +- .../java/org/traccar/protocol/T800xProtocol.java | 2 +- .../java/org/traccar/protocol/TaipProtocol.java | 2 +- .../java/org/traccar/protocol/TechTltProtocol.java | 2 +- .../org/traccar/protocol/TechtoCruzProtocol.java | 2 +- .../java/org/traccar/protocol/TekProtocol.java | 2 +- .../java/org/traccar/protocol/TelemaxProtocol.java | 2 +- .../java/org/traccar/protocol/TelicProtocol.java | 2 +- .../org/traccar/protocol/TeltonikaProtocol.java | 2 +- .../org/traccar/protocol/TeraTrackProtocol.java | 2 +- .../traccar/protocol/TeraTrackProtocolDecoder.java | 4 +- .../org/traccar/protocol/ThinkPowerProtocol.java | 2 +- .../org/traccar/protocol/ThinkRaceProtocol.java | 2 +- .../java/org/traccar/protocol/ThurayaProtocol.java | 2 +- .../java/org/traccar/protocol/Tk102Protocol.java | 2 +- .../java/org/traccar/protocol/Tk103Protocol.java | 2 +- .../java/org/traccar/protocol/Tlt2hProtocol.java | 2 +- .../java/org/traccar/protocol/TlvProtocol.java | 2 +- .../java/org/traccar/protocol/TmgProtocol.java | 2 +- .../org/traccar/protocol/TopflytechProtocol.java | 2 +- .../java/org/traccar/protocol/TopinProtocol.java | 2 +- .../java/org/traccar/protocol/TotemProtocol.java | 2 +- .../java/org/traccar/protocol/Tr20Protocol.java | 2 +- .../java/org/traccar/protocol/Tr900Protocol.java | 2 +- .../org/traccar/protocol/TrackboxProtocol.java | 2 +- .../org/traccar/protocol/TrakMateProtocol.java | 2 +- .../java/org/traccar/protocol/TramigoProtocol.java | 2 +- .../org/traccar/protocol/TranSyncProtocol.java | 2 +- .../java/org/traccar/protocol/TrvProtocol.java | 2 +- .../java/org/traccar/protocol/Tt8850Protocol.java | 2 +- .../java/org/traccar/protocol/TytanProtocol.java | 2 +- .../java/org/traccar/protocol/TzoneProtocol.java | 2 +- .../org/traccar/protocol/UlbotechProtocol.java | 2 +- .../java/org/traccar/protocol/UproProtocol.java | 2 +- .../java/org/traccar/protocol/UuxProtocol.java | 2 +- .../java/org/traccar/protocol/V680Protocol.java | 2 +- .../org/traccar/protocol/VisiontekProtocol.java | 2 +- .../java/org/traccar/protocol/VltProtocol.java | 2 +- .../java/org/traccar/protocol/VnetProtocol.java | 2 +- .../java/org/traccar/protocol/Vt200Protocol.java | 2 +- .../java/org/traccar/protocol/VtfmsProtocol.java | 2 +- .../java/org/traccar/protocol/WatchProtocol.java | 2 +- .../java/org/traccar/protocol/WialonProtocol.java | 2 +- .../java/org/traccar/protocol/WliProtocol.java | 2 +- .../java/org/traccar/protocol/WondexProtocol.java | 2 +- .../org/traccar/protocol/WristbandProtocol.java | 2 +- .../java/org/traccar/protocol/Xexun2Protocol.java | 2 +- .../java/org/traccar/protocol/XexunProtocol.java | 2 +- .../java/org/traccar/protocol/XirgoProtocol.java | 2 +- .../java/org/traccar/protocol/Xrb28Protocol.java | 2 +- .../java/org/traccar/protocol/Xt013Protocol.java | 2 +- .../java/org/traccar/protocol/Xt2400Protocol.java | 2 +- .../java/org/traccar/protocol/YwtProtocol.java | 2 +- .../traccar/reports/CombinedReportProvider.java | 2 +- .../org/traccar/reports/CsvExportProvider.java | 2 +- .../org/traccar/reports/EventsReportProvider.java | 2 +- .../org/traccar/reports/GpxExportProvider.java | 2 +- .../org/traccar/reports/KmlExportProvider.java | 2 +- .../org/traccar/reports/RouteReportProvider.java | 2 +- .../org/traccar/reports/StopsReportProvider.java | 2 +- .../org/traccar/reports/SummaryReportProvider.java | 2 +- .../org/traccar/reports/TripsReportProvider.java | 2 +- .../org/traccar/reports/common/ReportMailer.java | 10 ++--- .../org/traccar/reports/common/ReportUtils.java | 4 +- .../java/org/traccar/schedule/ScheduleManager.java | 4 +- .../schedule/TaskDeviceInactivityCheck.java | 2 +- .../java/org/traccar/schedule/TaskHealthCheck.java | 4 +- .../java/org/traccar/schedule/TaskReports.java | 2 +- .../traccar/schedule/TaskWebSocketKeepalive.java | 2 +- .../org/traccar/session/ConnectionManager.java | 4 +- .../org/traccar/session/cache/CacheManager.java | 4 +- src/main/java/org/traccar/sms/HttpSmsClient.java | 10 ++--- .../speedlimit/OverpassSpeedLimitProvider.java | 10 ++--- .../java/org/traccar/storage/DatabaseModule.java | 2 +- .../java/org/traccar/storage/DatabaseStorage.java | 2 +- src/main/java/org/traccar/web/ConsoleServlet.java | 8 ++-- .../java/org/traccar/web/ModernDefaultServlet.java | 2 +- src/main/java/org/traccar/web/OverrideFilter.java | 18 ++++---- src/main/java/org/traccar/web/ResponseWrapper.java | 8 ++-- .../java/org/traccar/web/ThrottlingFilter.java | 14 +++--- .../traccar/web/WebInjectionManagerFactory.java | 2 +- src/main/java/org/traccar/web/WebServer.java | 10 ++--- .../java/org/traccar/geocoder/GeocoderTest.java | 4 +- .../geolocation/GeolocationProviderTest.java | 4 +- .../java/org/traccar/helper/WebHelperTest.java | 2 +- .../notification/NotificiationMailTest.java | 10 ++--- .../speedlimit/OverpassSpeedLimitProviderTest.java | 4 +- 418 files changed, 835 insertions(+), 835 deletions(-) diff --git a/build.gradle b/build.gradle index d08dfebc5..06516794c 100644 --- a/build.gradle +++ b/build.gradle @@ -26,13 +26,13 @@ enforce { } ext { - guiceVersion = "6.0.0" - jettyVersion = "10.0.15" // jetty 11 javax to jakarta - jerseyVersion = "2.39.1" // jersey 3 javax to jakarta - jacksonVersion = "2.14.1" // same version as jersey-media-json-jackson dependency - protobufVersion = "3.23.2" - jxlsVersion = "2.12.0" - junitVersion = "5.9.3" + guiceVersion = "7.0.0" + jettyVersion = "11.0.15" + jerseyVersion = "3.1.3" + jacksonVersion = "2.15.2" // same version as jersey-media-json-jackson dependency + protobufVersion = "3.24.0" + jxlsVersion = "2.13.0" + junitVersion = "5.10.0" } protobuf { @@ -42,19 +42,20 @@ protobuf { } dependencies { - implementation "commons-codec:commons-codec:1.15" - implementation "com.h2database:h2:2.1.214" - implementation "com.mysql:mysql-connector-j:8.0.33" + implementation "commons-codec:commons-codec:1.16.0" + implementation "com.h2database:h2:2.2.220" + implementation "com.mysql:mysql-connector-j:8.1.0" implementation "org.mariadb.jdbc:mariadb-java-client:3.1.4" implementation "org.postgresql:postgresql:42.6.0" - implementation "com.microsoft.sqlserver:mssql-jdbc:12.2.0.jre11" + implementation "com.microsoft.sqlserver:mssql-jdbc:12.4.0.jre11" implementation "com.zaxxer:HikariCP:5.0.1" - implementation "io.netty:netty-all:4.1.93.Final" + implementation "io.netty:netty-all:4.1.96.Final" implementation "org.slf4j:slf4j-jdk14:2.0.7" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" - implementation "org.glassfish:jakarta.json:1.1.6" + implementation "org.glassfish:jakarta.json:2.0.1" + implementation "com.sun.mail:jakarta.mail:2.0.1" implementation "org.eclipse.jetty:jetty-server:$jettyVersion" implementation "org.eclipse.jetty:jetty-servlet:$jettyVersion" implementation "org.eclipse.jetty:jetty-servlets:$jettyVersion" @@ -65,34 +66,33 @@ dependencies { implementation "org.glassfish.jersey.containers:jersey-container-servlet:$jerseyVersion" implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion" implementation "org.glassfish.jersey.inject:jersey-hk2:$jerseyVersion" - implementation "org.glassfish.hk2:guice-bridge:2.6.1" // same version as jersey-hk2 + implementation "org.glassfish.hk2:guice-bridge:3.0.4" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" - implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.22.0" - implementation "com.sun.mail:jakarta.mail:1.6.7" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp:$jacksonVersion" + implementation "org.liquibase:liquibase-core:4.23.1" implementation "org.apache.commons:commons-jexl3:3.3" implementation "org.jxls:jxls:$jxlsVersion" implementation "org.jxls:jxls-poi:$jxlsVersion" implementation "org.apache.velocity:velocity-engine-core:2.3" implementation "org.apache.velocity.tools:velocity-tools-generic:3.1" implementation "org.apache.commons:commons-collections4:4.4" - implementation "org.mnode.ical4j:ical4j:3.2.11" + implementation "org.mnode.ical4j:ical4j:3.2.12" implementation "org.locationtech.spatial4j:spatial4j:0.8" implementation "org.locationtech.jts:jts-core:1.19.0" implementation "net.java.dev.jna:jna-platform:5.13.0" - implementation "com.github.jnr:jnr-posix:3.1.16" + implementation "com.github.jnr:jnr-posix:3.1.17" implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation "javax.activation:activation:1.1.1" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.477" - implementation "org.apache.kafka:kafka-clients:3.4.0" + implementation "com.amazonaws:aws-java-sdk-sns:1.12.532" + implementation "org.apache.kafka:kafka-clients:3.5.1" implementation "com.hivemq:hivemq-mqtt-client:1.3.1" - implementation "redis.clients:jedis:4.4.1" - implementation "com.google.firebase:firebase-admin:9.1.1" - implementation "com.nimbusds:oauth2-oidc-sdk:10.9.1" + implementation "redis.clients:jedis:4.4.3" + implementation "com.google.firebase:firebase-admin:9.2.0" + implementation "com.nimbusds:oauth2-oidc-sdk:10.13.2" implementation "com.rabbitmq:amqp-client:5.18.0" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:5.3.1" + testImplementation "org.mockito:mockito-core:5.4.0" } test { diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index 1948becc0..ea302997c 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -23,8 +23,8 @@ import org.traccar.helper.DataConverter; import org.traccar.model.Command; import org.traccar.sms.SmsManager; -import javax.annotation.Nullable; -import javax.inject.Inject; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; import java.net.SocketAddress; import java.util.Arrays; import java.util.Collection; diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 382daf92f..69ca0ccc6 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -31,7 +31,7 @@ import org.traccar.session.DeviceSession; import org.traccar.session.cache.CacheManager; import org.traccar.storage.StorageException; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Collection; diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java index 96de3e3f0..b9ca16838 100644 --- a/src/main/java/org/traccar/BaseProtocolEncoder.java +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -27,7 +27,7 @@ import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; +import jakarta.inject.Inject; public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter { diff --git a/src/main/java/org/traccar/ExtendedObjectDecoder.java b/src/main/java/org/traccar/ExtendedObjectDecoder.java index 805f98cb7..cddddcd80 100644 --- a/src/main/java/org/traccar/ExtendedObjectDecoder.java +++ b/src/main/java/org/traccar/ExtendedObjectDecoder.java @@ -27,7 +27,7 @@ import org.traccar.handler.AcknowledgementHandler; import org.traccar.helper.DataConverter; import org.traccar.model.Position; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.Collection; diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index 658ff6d6d..fb0171d63 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -41,8 +41,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index f5db75846..6ed240d2c 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -17,7 +17,7 @@ package org.traccar; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsr353.JSR353Module; +import com.fasterxml.jackson.datatype.jsonp.JSONPModule; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Provides; @@ -93,10 +93,10 @@ import org.traccar.storage.Storage; import org.traccar.web.WebServer; import org.traccar.api.security.LoginService; -import javax.annotation.Nullable; -import javax.inject.Singleton; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; +import jakarta.annotation.Nullable; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; import java.io.IOException; import java.net.URISyntaxException; import java.net.http.HttpClient; @@ -134,7 +134,7 @@ public class MainModule extends AbstractModule { if (config.getBoolean(Keys.WEB_SANITIZE)) { objectMapper.registerModule(new SanitizerModule()); } - objectMapper.registerModule(new JSR353Module()); + objectMapper.registerModule(new JSONPModule()); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return objectMapper; } diff --git a/src/main/java/org/traccar/PositionForwardingHandler.java b/src/main/java/org/traccar/PositionForwardingHandler.java index 83f91e937..a79b01367 100644 --- a/src/main/java/org/traccar/PositionForwardingHandler.java +++ b/src/main/java/org/traccar/PositionForwardingHandler.java @@ -30,9 +30,9 @@ import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java index 57afb01fd..e91be50a2 100644 --- a/src/main/java/org/traccar/ServerManager.java +++ b/src/main/java/org/traccar/ServerManager.java @@ -22,8 +22,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.ClassScanner; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.IOException; import java.net.BindException; import java.net.ConnectException; diff --git a/src/main/java/org/traccar/api/AsyncSocketServlet.java b/src/main/java/org/traccar/api/AsyncSocketServlet.java index 91a745eeb..cd2c1639e 100644 --- a/src/main/java/org/traccar/api/AsyncSocketServlet.java +++ b/src/main/java/org/traccar/api/AsyncSocketServlet.java @@ -24,9 +24,9 @@ import org.traccar.config.Keys; import org.traccar.session.ConnectionManager; import org.traccar.storage.Storage; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.servlet.http.HttpSession; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.servlet.http.HttpSession; import java.time.Duration; @Singleton diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index b007b7bcd..2aaed2bb5 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -29,14 +29,14 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.core.Response; public abstract class BaseObjectResource extends BaseResource { diff --git a/src/main/java/org/traccar/api/BaseResource.java b/src/main/java/org/traccar/api/BaseResource.java index 33abe73fa..f20b8c4c2 100644 --- a/src/main/java/org/traccar/api/BaseResource.java +++ b/src/main/java/org/traccar/api/BaseResource.java @@ -19,9 +19,9 @@ import org.traccar.api.security.PermissionsService; import org.traccar.api.security.UserPrincipal; import org.traccar.storage.Storage; -import javax.inject.Inject; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.SecurityContext; +import jakarta.inject.Inject; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.SecurityContext; public class BaseResource { diff --git a/src/main/java/org/traccar/api/CorsResponseFilter.java b/src/main/java/org/traccar/api/CorsResponseFilter.java index 67d0341a1..a380eb41d 100644 --- a/src/main/java/org/traccar/api/CorsResponseFilter.java +++ b/src/main/java/org/traccar/api/CorsResponseFilter.java @@ -19,11 +19,11 @@ import io.netty.handler.codec.http.HttpHeaderNames; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.container.ContainerResponseFilter; import java.io.IOException; @Singleton diff --git a/src/main/java/org/traccar/api/DateParameterConverterProvider.java b/src/main/java/org/traccar/api/DateParameterConverterProvider.java index f07ece984..4858fcbfd 100644 --- a/src/main/java/org/traccar/api/DateParameterConverterProvider.java +++ b/src/main/java/org/traccar/api/DateParameterConverterProvider.java @@ -17,8 +17,8 @@ package org.traccar.api; import org.traccar.helper.DateUtil; -import javax.ws.rs.ext.ParamConverter; -import javax.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Date; diff --git a/src/main/java/org/traccar/api/ExtendedObjectResource.java b/src/main/java/org/traccar/api/ExtendedObjectResource.java index 8467b46c6..348ebe38a 100644 --- a/src/main/java/org/traccar/api/ExtendedObjectResource.java +++ b/src/main/java/org/traccar/api/ExtendedObjectResource.java @@ -25,8 +25,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.ws.rs.GET; -import javax.ws.rs.QueryParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.QueryParam; import java.util.Collection; import java.util.LinkedList; diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java index e6556189a..38d13078d 100644 --- a/src/main/java/org/traccar/api/MediaFilter.java +++ b/src/main/java/org/traccar/api/MediaFilter.java @@ -28,16 +28,16 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import java.io.IOException; @Singleton diff --git a/src/main/java/org/traccar/api/ResourceErrorHandler.java b/src/main/java/org/traccar/api/ResourceErrorHandler.java index 108a8e8cc..387f3db6a 100644 --- a/src/main/java/org/traccar/api/ResourceErrorHandler.java +++ b/src/main/java/org/traccar/api/ResourceErrorHandler.java @@ -17,9 +17,9 @@ package org.traccar.api; import org.traccar.helper.Log; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; public class ResourceErrorHandler implements ExceptionMapper { diff --git a/src/main/java/org/traccar/api/SimpleObjectResource.java b/src/main/java/org/traccar/api/SimpleObjectResource.java index 4a435ca7d..c9d41b063 100644 --- a/src/main/java/org/traccar/api/SimpleObjectResource.java +++ b/src/main/java/org/traccar/api/SimpleObjectResource.java @@ -23,8 +23,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.ws.rs.GET; -import javax.ws.rs.QueryParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.QueryParam; import java.util.Collection; import java.util.LinkedList; diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java index f85e90133..44f0ef452 100644 --- a/src/main/java/org/traccar/api/resource/AttributeResource.java +++ b/src/main/java/org/traccar/api/resource/AttributeResource.java @@ -16,17 +16,17 @@ */ package org.traccar.api.resource; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import org.traccar.api.ExtendedObjectResource; import org.traccar.model.Attribute; diff --git a/src/main/java/org/traccar/api/resource/CalendarResource.java b/src/main/java/org/traccar/api/resource/CalendarResource.java index 9399c34a5..f6c1f3c59 100644 --- a/src/main/java/org/traccar/api/resource/CalendarResource.java +++ b/src/main/java/org/traccar/api/resource/CalendarResource.java @@ -16,10 +16,10 @@ */ package org.traccar.api.resource; -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import org.traccar.api.SimpleObjectResource; import org.traccar.model.Calendar; diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index 3df2244d1..d50c7ee0c 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -37,15 +37,15 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index c0b0cea0d..61a70bac0 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -30,19 +30,19 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.io.File; import java.io.FileInputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/api/resource/DriverResource.java b/src/main/java/org/traccar/api/resource/DriverResource.java index 91aa54c5e..19cf74f39 100644 --- a/src/main/java/org/traccar/api/resource/DriverResource.java +++ b/src/main/java/org/traccar/api/resource/DriverResource.java @@ -16,10 +16,10 @@ */ package org.traccar.api.resource; -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import org.traccar.api.ExtendedObjectResource; import org.traccar.model.Driver; diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java index afdaf52b5..1f20b880d 100644 --- a/src/main/java/org/traccar/api/resource/EventResource.java +++ b/src/main/java/org/traccar/api/resource/EventResource.java @@ -23,14 +23,14 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; @Path("events") @Produces(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/traccar/api/resource/GeofenceResource.java b/src/main/java/org/traccar/api/resource/GeofenceResource.java index 58f2c188c..030690889 100644 --- a/src/main/java/org/traccar/api/resource/GeofenceResource.java +++ b/src/main/java/org/traccar/api/resource/GeofenceResource.java @@ -18,10 +18,10 @@ package org.traccar.api.resource; import org.traccar.api.ExtendedObjectResource; import org.traccar.model.Geofence; -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; @Path("geofences") @Produces(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/traccar/api/resource/GroupResource.java b/src/main/java/org/traccar/api/resource/GroupResource.java index fcea15d0a..628f8f655 100644 --- a/src/main/java/org/traccar/api/resource/GroupResource.java +++ b/src/main/java/org/traccar/api/resource/GroupResource.java @@ -18,10 +18,10 @@ package org.traccar.api.resource; import org.traccar.api.SimpleObjectResource; import org.traccar.model.Group; -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; @Path("groups") @Produces(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/traccar/api/resource/MaintenanceResource.java b/src/main/java/org/traccar/api/resource/MaintenanceResource.java index fa1b359ce..12841e497 100644 --- a/src/main/java/org/traccar/api/resource/MaintenanceResource.java +++ b/src/main/java/org/traccar/api/resource/MaintenanceResource.java @@ -16,10 +16,10 @@ */ package org.traccar.api.resource; -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import org.traccar.api.ExtendedObjectResource; import org.traccar.model.Maintenance; diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java index 7005fc083..2a209efb6 100644 --- a/src/main/java/org/traccar/api/resource/NotificationResource.java +++ b/src/main/java/org/traccar/api/resource/NotificationResource.java @@ -26,15 +26,15 @@ import org.traccar.notification.MessageException; import org.traccar.notification.NotificatorManager; import org.traccar.storage.StorageException; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; diff --git a/src/main/java/org/traccar/api/resource/OrderResource.java b/src/main/java/org/traccar/api/resource/OrderResource.java index 77608a508..3852b975f 100644 --- a/src/main/java/org/traccar/api/resource/OrderResource.java +++ b/src/main/java/org/traccar/api/resource/OrderResource.java @@ -18,10 +18,10 @@ package org.traccar.api.resource; import org.traccar.api.SimpleObjectResource; import org.traccar.model.Order; -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; @Path("orders") @Produces(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 67c9cee97..029e63a0c 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -25,16 +25,16 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.mail.MessagingException; -import javax.ws.rs.Consumes; -import javax.ws.rs.FormParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.annotation.security.PermitAll; +import jakarta.inject.Inject; +import jakarta.mail.MessagingException; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.io.IOException; import java.security.GeneralSecurityException; diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java index f02c5d426..e8e4e96eb 100644 --- a/src/main/java/org/traccar/api/resource/PermissionsResource.java +++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java @@ -23,15 +23,15 @@ import org.traccar.model.UserRestrictions; import org.traccar.session.cache.CacheManager; import org.traccar.storage.StorageException; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 37696a620..0d783a0fe 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -28,18 +28,18 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.DELETE; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.StreamingOutput; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.StreamingOutput; import java.util.ArrayList; import java.util.Collection; import java.util.Date; diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index e392f3f90..b4882f219 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -36,18 +36,18 @@ import org.traccar.reports.model.SummaryReportItem; import org.traccar.reports.model.TripReportItem; import org.traccar.storage.StorageException; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.StreamingOutput; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.StreamingOutput; import java.util.Collection; import java.util.Date; import java.util.List; diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index dcb059b69..8149ec3b8 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -33,19 +33,19 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.annotation.Nullable; -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.annotation.Nullable; +import jakarta.annotation.security.PermitAll; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 9b6a74ddb..3e738c15a 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -29,24 +29,24 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; import com.nimbusds.oauth2.sdk.ParseException; -import javax.annotation.Nullable; -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.annotation.Nullable; +import jakarta.annotation.security.PermitAll; +import jakarta.inject.Inject; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.io.IOException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/api/resource/StatisticsResource.java b/src/main/java/org/traccar/api/resource/StatisticsResource.java index 1f2296f28..0c728c77d 100644 --- a/src/main/java/org/traccar/api/resource/StatisticsResource.java +++ b/src/main/java/org/traccar/api/resource/StatisticsResource.java @@ -23,12 +23,12 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import java.util.Collection; import java.util.Date; diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 19d88782f..cbee3bd4a 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -27,16 +27,16 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.annotation.security.PermitAll; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.util.Collection; @Path("users") diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index db9ed6cff..91e964ee9 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -27,9 +27,9 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.IOException; import java.security.GeneralSecurityException; diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index 7f5a46225..d60bbafb8 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -34,7 +34,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.util.Objects; @RequestScoped diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index e6641548a..a34361854 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -24,16 +24,16 @@ import org.traccar.helper.DataConverter; import org.traccar.model.User; import org.traccar.storage.StorageException; -import javax.annotation.security.PermitAll; -import javax.inject.Inject; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.container.ResourceInfo; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; +import jakarta.annotation.security.PermitAll; +import jakarta.inject.Inject; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.container.ResourceInfo; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; import java.io.IOException; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/api/security/UserSecurityContext.java b/src/main/java/org/traccar/api/security/UserSecurityContext.java index 97df6b6c7..f7adeac64 100644 --- a/src/main/java/org/traccar/api/security/UserSecurityContext.java +++ b/src/main/java/org/traccar/api/security/UserSecurityContext.java @@ -15,7 +15,7 @@ */ package org.traccar.api.security; -import javax.ws.rs.core.SecurityContext; +import jakarta.ws.rs.core.SecurityContext; import java.security.Principal; public class UserSecurityContext implements SecurityContext { diff --git a/src/main/java/org/traccar/api/signature/CryptoManager.java b/src/main/java/org/traccar/api/signature/CryptoManager.java index 249d5bd97..71f56e0fb 100644 --- a/src/main/java/org/traccar/api/signature/CryptoManager.java +++ b/src/main/java/org/traccar/api/signature/CryptoManager.java @@ -20,8 +20,8 @@ import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.KeyPair; diff --git a/src/main/java/org/traccar/api/signature/TokenManager.java b/src/main/java/org/traccar/api/signature/TokenManager.java index 6a0d90b40..3019e12b9 100644 --- a/src/main/java/org/traccar/api/signature/TokenManager.java +++ b/src/main/java/org/traccar/api/signature/TokenManager.java @@ -20,8 +20,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.codec.binary.Base64; import org.traccar.storage.StorageException; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Date; diff --git a/src/main/java/org/traccar/config/Config.java b/src/main/java/org/traccar/config/Config.java index c73be6475..47e1f0707 100644 --- a/src/main/java/org/traccar/config/Config.java +++ b/src/main/java/org/traccar/config/Config.java @@ -19,8 +19,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.inject.name.Named; import org.traccar.helper.Log; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index df399cd7a..fb8f2f9d6 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -34,9 +34,9 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collection; import java.util.stream.Collectors; diff --git a/src/main/java/org/traccar/database/DeviceLookupService.java b/src/main/java/org/traccar/database/DeviceLookupService.java index 583b2ae35..6ec6841a1 100644 --- a/src/main/java/org/traccar/database/DeviceLookupService.java +++ b/src/main/java/org/traccar/database/DeviceLookupService.java @@ -29,8 +29,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/org/traccar/database/MediaManager.java b/src/main/java/org/traccar/database/MediaManager.java index c1ef810ee..2f2369c96 100644 --- a/src/main/java/org/traccar/database/MediaManager.java +++ b/src/main/java/org/traccar/database/MediaManager.java @@ -21,8 +21,8 @@ import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 32216dfc6..3a57788fb 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -38,9 +38,9 @@ import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Request; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index d0ec4e98d..312be8890 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -33,7 +33,7 @@ import java.security.GeneralSecurityException; import java.util.List; import java.util.Map; import java.io.IOException; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index 0e9931fba..445e53e7c 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -29,11 +29,11 @@ import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Form; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Form; import java.util.Calendar; import java.util.Date; import java.util.HashMap; diff --git a/src/main/java/org/traccar/forward/EventForwarderJson.java b/src/main/java/org/traccar/forward/EventForwarderJson.java index 7527d568a..df53d3d46 100644 --- a/src/main/java/org/traccar/forward/EventForwarderJson.java +++ b/src/main/java/org/traccar/forward/EventForwarderJson.java @@ -18,10 +18,10 @@ package org.traccar.forward; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.InvocationCallback; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.InvocationCallback; +import jakarta.ws.rs.core.Response; public class EventForwarderJson implements EventForwarder { diff --git a/src/main/java/org/traccar/forward/NetworkForwarder.java b/src/main/java/org/traccar/forward/NetworkForwarder.java index 0915aaa27..86c9a77f3 100644 --- a/src/main/java/org/traccar/forward/NetworkForwarder.java +++ b/src/main/java/org/traccar/forward/NetworkForwarder.java @@ -20,8 +20,8 @@ import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; diff --git a/src/main/java/org/traccar/forward/PositionForwarderJson.java b/src/main/java/org/traccar/forward/PositionForwarderJson.java index 27b96308e..a0ad8ffd0 100644 --- a/src/main/java/org/traccar/forward/PositionForwarderJson.java +++ b/src/main/java/org/traccar/forward/PositionForwarderJson.java @@ -20,12 +20,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.InvocationCallback; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.InvocationCallback; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; public class PositionForwarderJson implements PositionForwarder { diff --git a/src/main/java/org/traccar/forward/PositionForwarderUrl.java b/src/main/java/org/traccar/forward/PositionForwarderUrl.java index 53cc7ad24..33474d40b 100644 --- a/src/main/java/org/traccar/forward/PositionForwarderUrl.java +++ b/src/main/java/org/traccar/forward/PositionForwarderUrl.java @@ -23,9 +23,9 @@ import org.traccar.helper.Checksum; import org.traccar.model.Device; import org.traccar.model.Position; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.InvocationCallback; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.InvocationCallback; +import jakarta.ws.rs.core.Response; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/geocoder/BanGeocoder.java b/src/main/java/org/traccar/geocoder/BanGeocoder.java index f878a8bab..e2ff72311 100644 --- a/src/main/java/org/traccar/geocoder/BanGeocoder.java +++ b/src/main/java/org/traccar/geocoder/BanGeocoder.java @@ -20,9 +20,9 @@ package org.traccar.geocoder; * API documentation: https://adresse.data.gouv.fr/api */ -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class BanGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java index 01e33c2ea..bc3b15ce7 100644 --- a/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java +++ b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java @@ -16,9 +16,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class BingMapsGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/FactualGeocoder.java b/src/main/java/org/traccar/geocoder/FactualGeocoder.java index 384f46b0e..6c8891316 100644 --- a/src/main/java/org/traccar/geocoder/FactualGeocoder.java +++ b/src/main/java/org/traccar/geocoder/FactualGeocoder.java @@ -16,8 +16,8 @@ */ package org.traccar.geocoder; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class FactualGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java b/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java index 4748d6a2c..35a47bb88 100644 --- a/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java +++ b/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java @@ -15,9 +15,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class GeoapifyGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java index 2af95910f..80b00b3cc 100644 --- a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java +++ b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java @@ -15,8 +15,8 @@ */ package org.traccar.geocoder; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class GeocodeFarmGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java index 96491ece3..e88962e1a 100644 --- a/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java +++ b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java @@ -15,8 +15,8 @@ */ package org.traccar.geocoder; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class GeocodeXyzGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java index 0589eb000..062e795eb 100644 --- a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java +++ b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java @@ -15,8 +15,8 @@ */ package org.traccar.geocoder; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class GisgraphyGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/GoogleGeocoder.java b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java index 4d9ec8f36..93f128b46 100644 --- a/src/main/java/org/traccar/geocoder/GoogleGeocoder.java +++ b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java @@ -15,10 +15,10 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.ws.rs.client.Client; public class GoogleGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/HereGeocoder.java b/src/main/java/org/traccar/geocoder/HereGeocoder.java index eb639995e..2d1bc1bf4 100644 --- a/src/main/java/org/traccar/geocoder/HereGeocoder.java +++ b/src/main/java/org/traccar/geocoder/HereGeocoder.java @@ -15,8 +15,8 @@ */ package org.traccar.geocoder; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class HereGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/JsonGeocoder.java b/src/main/java/org/traccar/geocoder/JsonGeocoder.java index 6105e8cfd..f9b039f43 100644 --- a/src/main/java/org/traccar/geocoder/JsonGeocoder.java +++ b/src/main/java/org/traccar/geocoder/JsonGeocoder.java @@ -19,10 +19,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.database.StatisticsManager; -import javax.json.JsonObject; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.InvocationCallback; +import jakarta.json.JsonObject; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.InvocationCallback; import java.util.AbstractMap; import java.util.Collections; import java.util.LinkedHashMap; diff --git a/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java b/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java index f2ffe02d6..f304ffeff 100644 --- a/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java +++ b/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java @@ -15,7 +15,7 @@ */ package org.traccar.geocoder; -import javax.ws.rs.client.Client; +import jakarta.ws.rs.client.Client; public class LocationIqGeocoder extends NominatimGeocoder { diff --git a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java index 3f2554c6e..1b6c8adcc 100644 --- a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java +++ b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java @@ -16,9 +16,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class MapQuestGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java b/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java index 203f5f99b..24c9da2ad 100644 --- a/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java +++ b/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java @@ -15,9 +15,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class MapTilerGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/MapboxGeocoder.java b/src/main/java/org/traccar/geocoder/MapboxGeocoder.java index 72bfb53f5..9fa6b8d88 100644 --- a/src/main/java/org/traccar/geocoder/MapboxGeocoder.java +++ b/src/main/java/org/traccar/geocoder/MapboxGeocoder.java @@ -15,10 +15,10 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.ws.rs.client.Client; public class MapboxGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java index dea295cca..b68db07bc 100644 --- a/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java +++ b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java @@ -15,9 +15,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class MapmyIndiaGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/NominatimGeocoder.java b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java index b731549f7..1e26d0042 100644 --- a/src/main/java/org/traccar/geocoder/NominatimGeocoder.java +++ b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java @@ -15,8 +15,8 @@ */ package org.traccar.geocoder; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class NominatimGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java index fb61440aa..4607fdc87 100644 --- a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java +++ b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java @@ -16,9 +16,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class OpenCageGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java b/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java index 9778d9eda..4aed27fc5 100644 --- a/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java +++ b/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java @@ -15,9 +15,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class PositionStackGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geocoder/TomTomGeocoder.java b/src/main/java/org/traccar/geocoder/TomTomGeocoder.java index 9bb36efc2..4d452fd43 100644 --- a/src/main/java/org/traccar/geocoder/TomTomGeocoder.java +++ b/src/main/java/org/traccar/geocoder/TomTomGeocoder.java @@ -15,9 +15,9 @@ */ package org.traccar.geocoder; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; public class TomTomGeocoder extends JsonGeocoder { diff --git a/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java b/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java index 8f0f3b704..9425e9111 100644 --- a/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java +++ b/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java @@ -15,7 +15,7 @@ */ package org.traccar.geolocation; -import javax.ws.rs.client.Client; +import jakarta.ws.rs.client.Client; public class GoogleGeolocationProvider extends UniversalGeolocationProvider { diff --git a/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java b/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java index 3b4ba4e1f..7eb22dcca 100644 --- a/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java +++ b/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java @@ -15,7 +15,7 @@ */ package org.traccar.geolocation; -import javax.ws.rs.client.Client; +import jakarta.ws.rs.client.Client; public class MozillaGeolocationProvider extends UniversalGeolocationProvider { diff --git a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java index 82fcf42ab..72a05d10f 100644 --- a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java +++ b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java @@ -18,9 +18,9 @@ package org.traccar.geolocation; import org.traccar.model.CellTower; import org.traccar.model.Network; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.InvocationCallback; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.InvocationCallback; public class OpenCellIdGeolocationProvider implements GeolocationProvider { diff --git a/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java b/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java index 7a3f71ee1..9086d8ce3 100644 --- a/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java +++ b/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java @@ -17,10 +17,10 @@ package org.traccar.geolocation; import org.traccar.model.Network; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.InvocationCallback; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.InvocationCallback; public class UniversalGeolocationProvider implements GeolocationProvider { diff --git a/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java b/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java index 14893b6a3..4f1c5617e 100644 --- a/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java +++ b/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java @@ -23,10 +23,10 @@ import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.WifiAccessPoint; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.InvocationCallback; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.InvocationCallback; import java.util.Collection; public class UnwiredGeolocationProvider implements GeolocationProvider { diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 8ad4e41e4..042747359 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -43,8 +43,8 @@ import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java index e5c9bc29a..42b438e41 100644 --- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java +++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java @@ -24,8 +24,8 @@ import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/DefaultDataHandler.java b/src/main/java/org/traccar/handler/DefaultDataHandler.java index 89255a5fe..cca6dcd0a 100644 --- a/src/main/java/org/traccar/handler/DefaultDataHandler.java +++ b/src/main/java/org/traccar/handler/DefaultDataHandler.java @@ -24,8 +24,8 @@ import org.traccar.storage.Storage; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java index 30dc9ff2b..7fdefa1f4 100644 --- a/src/main/java/org/traccar/handler/DistanceHandler.java +++ b/src/main/java/org/traccar/handler/DistanceHandler.java @@ -24,8 +24,8 @@ import org.traccar.helper.DistanceCalculator; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.math.BigDecimal; import java.math.RoundingMode; diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java index c10fe9064..621205b34 100644 --- a/src/main/java/org/traccar/handler/EngineHoursHandler.java +++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java @@ -21,8 +21,8 @@ import org.traccar.BaseDataHandler; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 028e4cd09..a15d3ffad 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -36,8 +36,8 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Date; @Singleton diff --git a/src/main/java/org/traccar/handler/GeofenceHandler.java b/src/main/java/org/traccar/handler/GeofenceHandler.java index fe15cef8e..68bc6dbf0 100644 --- a/src/main/java/org/traccar/handler/GeofenceHandler.java +++ b/src/main/java/org/traccar/handler/GeofenceHandler.java @@ -22,8 +22,8 @@ import org.traccar.helper.model.GeofenceUtil; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.List; @Singleton diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java index ccbde9fe5..294e449db 100644 --- a/src/main/java/org/traccar/handler/HemisphereHandler.java +++ b/src/main/java/org/traccar/handler/HemisphereHandler.java @@ -21,8 +21,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java index 297527b4d..68a31a16a 100644 --- a/src/main/java/org/traccar/handler/MotionHandler.java +++ b/src/main/java/org/traccar/handler/MotionHandler.java @@ -23,8 +23,8 @@ import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java index 2c586c973..470e175ca 100644 --- a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java +++ b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java @@ -22,7 +22,7 @@ import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramPacket; import org.traccar.forward.NetworkForwarder; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.net.InetSocketAddress; import java.net.SocketAddress; diff --git a/src/main/java/org/traccar/handler/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/RemoteAddressHandler.java index e18d34ef2..61ada5b91 100644 --- a/src/main/java/org/traccar/handler/RemoteAddressHandler.java +++ b/src/main/java/org/traccar/handler/RemoteAddressHandler.java @@ -22,8 +22,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.net.InetSocketAddress; @Singleton diff --git a/src/main/java/org/traccar/handler/SpeedLimitHandler.java b/src/main/java/org/traccar/handler/SpeedLimitHandler.java index 0c6025999..6edb6e912 100644 --- a/src/main/java/org/traccar/handler/SpeedLimitHandler.java +++ b/src/main/java/org/traccar/handler/SpeedLimitHandler.java @@ -23,8 +23,8 @@ import org.slf4j.LoggerFactory; import org.traccar.model.Position; import org.traccar.speedlimit.SpeedLimitProvider; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java index c98b0bd4c..3c3e17450 100644 --- a/src/main/java/org/traccar/handler/TimeHandler.java +++ b/src/main/java/org/traccar/handler/TimeHandler.java @@ -23,8 +23,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Arrays; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/org/traccar/handler/events/AlertEventHandler.java b/src/main/java/org/traccar/handler/events/AlertEventHandler.java index 9f77df989..531a0f957 100644 --- a/src/main/java/org/traccar/handler/events/AlertEventHandler.java +++ b/src/main/java/org/traccar/handler/events/AlertEventHandler.java @@ -25,8 +25,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/events/BaseEventHandler.java b/src/main/java/org/traccar/handler/events/BaseEventHandler.java index 271aaa35d..4a4fb40ff 100644 --- a/src/main/java/org/traccar/handler/events/BaseEventHandler.java +++ b/src/main/java/org/traccar/handler/events/BaseEventHandler.java @@ -22,7 +22,7 @@ import org.traccar.database.NotificationManager; import org.traccar.model.Event; import org.traccar.model.Position; -import javax.inject.Inject; +import jakarta.inject.Inject; public abstract class BaseEventHandler extends BaseDataHandler { diff --git a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java index 51bbd82d6..08ae35fcd 100644 --- a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java +++ b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java @@ -23,8 +23,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java index 772176e9c..b70f8f33b 100644 --- a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java +++ b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java @@ -22,8 +22,8 @@ import io.netty.channel.ChannelHandler; import org.traccar.model.Event; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/events/DriverEventHandler.java b/src/main/java/org/traccar/handler/events/DriverEventHandler.java index 51fdc0307..b68327983 100644 --- a/src/main/java/org/traccar/handler/events/DriverEventHandler.java +++ b/src/main/java/org/traccar/handler/events/DriverEventHandler.java @@ -22,8 +22,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/org/traccar/handler/events/FuelEventHandler.java b/src/main/java/org/traccar/handler/events/FuelEventHandler.java index a1584d4e4..e5085ecc2 100644 --- a/src/main/java/org/traccar/handler/events/FuelEventHandler.java +++ b/src/main/java/org/traccar/handler/events/FuelEventHandler.java @@ -24,8 +24,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Map; @Singleton diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index 096f71373..dbe2b8118 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -23,8 +23,8 @@ import org.traccar.model.Geofence; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.ArrayList; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java index b2e9a3325..ba4159a42 100644 --- a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java @@ -26,8 +26,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java index 909950acf..6c4271ce2 100644 --- a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java @@ -25,8 +25,8 @@ import org.traccar.model.Maintenance; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/events/MediaEventHandler.java b/src/main/java/org/traccar/handler/events/MediaEventHandler.java index a49e08e8d..52d8e6961 100644 --- a/src/main/java/org/traccar/handler/events/MediaEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MediaEventHandler.java @@ -19,8 +19,8 @@ import io.netty.channel.ChannelHandler; import org.traccar.model.Event; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index d2c54ccf3..15902d6d4 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -35,8 +35,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 40f1c7442..94fdc4699 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -36,8 +36,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java index b40e30d76..634950b85 100644 --- a/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java +++ b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java @@ -17,8 +17,8 @@ package org.traccar.helper; import com.fasterxml.jackson.databind.ObjectMapper; -import javax.inject.Inject; -import javax.ws.rs.ext.ContextResolver; +import jakarta.inject.Inject; +import jakarta.ws.rs.ext.ContextResolver; // This does not work as a lambda public class ObjectMapperContextResolver implements ContextResolver { diff --git a/src/main/java/org/traccar/helper/WebHelper.java b/src/main/java/org/traccar/helper/WebHelper.java index e2844bc4d..9533fe84b 100644 --- a/src/main/java/org/traccar/helper/WebHelper.java +++ b/src/main/java/org/traccar/helper/WebHelper.java @@ -18,7 +18,7 @@ package org.traccar.helper; import java.net.InetAddress; import java.net.UnknownHostException; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.eclipse.jetty.util.URIUtil; import org.traccar.config.Config; diff --git a/src/main/java/org/traccar/mail/LogMailManager.java b/src/main/java/org/traccar/mail/LogMailManager.java index 5c7572b0c..90de3bcce 100644 --- a/src/main/java/org/traccar/mail/LogMailManager.java +++ b/src/main/java/org/traccar/mail/LogMailManager.java @@ -19,8 +19,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.model.User; -import javax.mail.MessagingException; -import javax.mail.internet.MimeBodyPart; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeBodyPart; public class LogMailManager implements MailManager { diff --git a/src/main/java/org/traccar/mail/MailManager.java b/src/main/java/org/traccar/mail/MailManager.java index 3547fd37e..d05a07de9 100644 --- a/src/main/java/org/traccar/mail/MailManager.java +++ b/src/main/java/org/traccar/mail/MailManager.java @@ -17,8 +17,8 @@ package org.traccar.mail; import org.traccar.model.User; -import javax.mail.MessagingException; -import javax.mail.internet.MimeBodyPart; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeBodyPart; public interface MailManager { diff --git a/src/main/java/org/traccar/mail/SmtpMailManager.java b/src/main/java/org/traccar/mail/SmtpMailManager.java index 8d1afbd3e..70099d879 100644 --- a/src/main/java/org/traccar/mail/SmtpMailManager.java +++ b/src/main/java/org/traccar/mail/SmtpMailManager.java @@ -23,16 +23,16 @@ import org.traccar.database.StatisticsManager; import org.traccar.model.User; import org.traccar.notification.PropertiesProvider; -import javax.mail.BodyPart; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; +import jakarta.mail.BodyPart; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Multipart; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeBodyPart; +import jakarta.mail.internet.MimeMessage; +import jakarta.mail.internet.MimeMultipart; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.Properties; diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java index 9ee3b97b6..85e8a54bb 100644 --- a/src/main/java/org/traccar/notification/NotificationFormatter.java +++ b/src/main/java/org/traccar/notification/NotificationFormatter.java @@ -27,8 +27,8 @@ import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton public class NotificationFormatter { diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java index b6ee760f3..8d41ee354 100644 --- a/src/main/java/org/traccar/notification/NotificatorManager.java +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -30,8 +30,8 @@ import org.traccar.notificators.NotificatorTelegram; import org.traccar.notificators.NotificatorTraccar; import org.traccar.notificators.NotificatorWeb; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Arrays; import java.util.HashSet; import java.util.Map; diff --git a/src/main/java/org/traccar/notification/TextTemplateFormatter.java b/src/main/java/org/traccar/notification/TextTemplateFormatter.java index 444f4a7c2..ab90d76d4 100644 --- a/src/main/java/org/traccar/notification/TextTemplateFormatter.java +++ b/src/main/java/org/traccar/notification/TextTemplateFormatter.java @@ -29,8 +29,8 @@ import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.storage.StorageException; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/notificators/NotificatorCommand.java b/src/main/java/org/traccar/notificators/NotificatorCommand.java index 55cbe0a6a..5dd3313d4 100644 --- a/src/main/java/org/traccar/notificators/NotificatorCommand.java +++ b/src/main/java/org/traccar/notificators/NotificatorCommand.java @@ -27,8 +27,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton public class NotificatorCommand implements Notificator { diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index d80354d7d..be95fb28e 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -44,8 +44,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java index 8818a5a75..3ab050686 100644 --- a/src/main/java/org/traccar/notificators/NotificatorMail.java +++ b/src/main/java/org/traccar/notificators/NotificatorMail.java @@ -24,9 +24,9 @@ import org.traccar.model.User; import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.mail.MessagingException; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.mail.MessagingException; @Singleton public class NotificatorMail implements Notificator { diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 703d86876..9f2a8c94d 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -24,10 +24,10 @@ import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; @Singleton public class NotificatorPushover implements Notificator { diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java index 7ec47b156..2b6b20b1b 100644 --- a/src/main/java/org/traccar/notificators/NotificatorSms.java +++ b/src/main/java/org/traccar/notificators/NotificatorSms.java @@ -25,8 +25,8 @@ import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; import org.traccar.sms.SmsManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton public class NotificatorSms implements Notificator { diff --git a/src/main/java/org/traccar/notificators/NotificatorTelegram.java b/src/main/java/org/traccar/notificators/NotificatorTelegram.java index 63d2bb717..c91aaa4ff 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTelegram.java +++ b/src/main/java/org/traccar/notificators/NotificatorTelegram.java @@ -25,10 +25,10 @@ import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; @Singleton public class NotificatorTelegram implements Notificator { diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index fb9632ad0..e354adccb 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java @@ -31,12 +31,12 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.json.JsonObject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Response; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java index 51884074e..3a125db3c 100644 --- a/src/main/java/org/traccar/notificators/NotificatorWeb.java +++ b/src/main/java/org/traccar/notificators/NotificatorWeb.java @@ -23,8 +23,8 @@ import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; import org.traccar.session.ConnectionManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton public final class NotificatorWeb implements Notificator { diff --git a/src/main/java/org/traccar/protocol/AdmProtocol.java b/src/main/java/org/traccar/protocol/AdmProtocol.java index bab1d2339..3856dc906 100644 --- a/src/main/java/org/traccar/protocol/AdmProtocol.java +++ b/src/main/java/org/traccar/protocol/AdmProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AdmProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AisProtocol.java b/src/main/java/org/traccar/protocol/AisProtocol.java index bc975c277..e792a1d3f 100644 --- a/src/main/java/org/traccar/protocol/AisProtocol.java +++ b/src/main/java/org/traccar/protocol/AisProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AisProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AlematicsProtocol.java b/src/main/java/org/traccar/protocol/AlematicsProtocol.java index b85b44382..5219607e7 100644 --- a/src/main/java/org/traccar/protocol/AlematicsProtocol.java +++ b/src/main/java/org/traccar/protocol/AlematicsProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AlematicsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AnytrekProtocol.java b/src/main/java/org/traccar/protocol/AnytrekProtocol.java index b0e974c69..5dce15ce1 100644 --- a/src/main/java/org/traccar/protocol/AnytrekProtocol.java +++ b/src/main/java/org/traccar/protocol/AnytrekProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AnytrekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ApelProtocol.java b/src/main/java/org/traccar/protocol/ApelProtocol.java index f1d6e659c..550581b85 100644 --- a/src/main/java/org/traccar/protocol/ApelProtocol.java +++ b/src/main/java/org/traccar/protocol/ApelProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ApelProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AplicomProtocol.java b/src/main/java/org/traccar/protocol/AplicomProtocol.java index 47bb780cb..48c628d22 100644 --- a/src/main/java/org/traccar/protocol/AplicomProtocol.java +++ b/src/main/java/org/traccar/protocol/AplicomProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AplicomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AppelloProtocol.java b/src/main/java/org/traccar/protocol/AppelloProtocol.java index 25b2bf3b8..34055d7e4 100644 --- a/src/main/java/org/traccar/protocol/AppelloProtocol.java +++ b/src/main/java/org/traccar/protocol/AppelloProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AppelloProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AquilaProtocol.java b/src/main/java/org/traccar/protocol/AquilaProtocol.java index 6080df33d..bd9c34d08 100644 --- a/src/main/java/org/traccar/protocol/AquilaProtocol.java +++ b/src/main/java/org/traccar/protocol/AquilaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AquilaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Ardi01Protocol.java b/src/main/java/org/traccar/protocol/Ardi01Protocol.java index b33c2817f..5ddbe9d62 100644 --- a/src/main/java/org/traccar/protocol/Ardi01Protocol.java +++ b/src/main/java/org/traccar/protocol/Ardi01Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Ardi01Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArknavProtocol.java b/src/main/java/org/traccar/protocol/ArknavProtocol.java index 4f443aa3a..20fec296c 100644 --- a/src/main/java/org/traccar/protocol/ArknavProtocol.java +++ b/src/main/java/org/traccar/protocol/ArknavProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArknavProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArknavX8Protocol.java b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java index 39c6e8009..a8be6f40c 100644 --- a/src/main/java/org/traccar/protocol/ArknavX8Protocol.java +++ b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArknavX8Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArmoliProtocol.java b/src/main/java/org/traccar/protocol/ArmoliProtocol.java index 32fba3b52..e9c947ecd 100644 --- a/src/main/java/org/traccar/protocol/ArmoliProtocol.java +++ b/src/main/java/org/traccar/protocol/ArmoliProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArmoliProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocol.java b/src/main/java/org/traccar/protocol/ArnaviProtocol.java index 091d5c06f..962bcce52 100644 --- a/src/main/java/org/traccar/protocol/ArnaviProtocol.java +++ b/src/main/java/org/traccar/protocol/ArnaviProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArnaviProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java index 361eeeef2..50ceea898 100644 --- a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java @@ -21,7 +21,7 @@ import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.Protocol; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.net.SocketAddress; public class ArnaviProtocolDecoder extends BaseProtocolDecoder { diff --git a/src/main/java/org/traccar/protocol/AstraProtocol.java b/src/main/java/org/traccar/protocol/AstraProtocol.java index 021a81e07..dcc02d10d 100644 --- a/src/main/java/org/traccar/protocol/AstraProtocol.java +++ b/src/main/java/org/traccar/protocol/AstraProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AstraProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/At2000Protocol.java b/src/main/java/org/traccar/protocol/At2000Protocol.java index 25e9be86f..c7e22f142 100644 --- a/src/main/java/org/traccar/protocol/At2000Protocol.java +++ b/src/main/java/org/traccar/protocol/At2000Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class At2000Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AtrackProtocol.java b/src/main/java/org/traccar/protocol/AtrackProtocol.java index 21eb09696..8b86955f4 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocol.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AtrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AuroProtocol.java b/src/main/java/org/traccar/protocol/AuroProtocol.java index d37884c8b..728c8e23c 100644 --- a/src/main/java/org/traccar/protocol/AuroProtocol.java +++ b/src/main/java/org/traccar/protocol/AuroProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AuroProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AustinNbProtocol.java b/src/main/java/org/traccar/protocol/AustinNbProtocol.java index 6a68467e2..467deff53 100644 --- a/src/main/java/org/traccar/protocol/AustinNbProtocol.java +++ b/src/main/java/org/traccar/protocol/AustinNbProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AustinNbProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AutoFonProtocol.java b/src/main/java/org/traccar/protocol/AutoFonProtocol.java index 0566b1da6..75bd28d5e 100644 --- a/src/main/java/org/traccar/protocol/AutoFonProtocol.java +++ b/src/main/java/org/traccar/protocol/AutoFonProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AutoFonProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AutoGradeProtocol.java b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java index bc80e473a..69d9fb4e6 100644 --- a/src/main/java/org/traccar/protocol/AutoGradeProtocol.java +++ b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AutoGradeProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AutoTrackProtocol.java b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java index 80255d3e9..df489de3c 100644 --- a/src/main/java/org/traccar/protocol/AutoTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AutoTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AvemaProtocol.java b/src/main/java/org/traccar/protocol/AvemaProtocol.java index b35a447ff..0eeee41b8 100644 --- a/src/main/java/org/traccar/protocol/AvemaProtocol.java +++ b/src/main/java/org/traccar/protocol/AvemaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AvemaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Avl301Protocol.java b/src/main/java/org/traccar/protocol/Avl301Protocol.java index c4a0affdc..452bc1501 100644 --- a/src/main/java/org/traccar/protocol/Avl301Protocol.java +++ b/src/main/java/org/traccar/protocol/Avl301Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Avl301Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/B2316Protocol.java b/src/main/java/org/traccar/protocol/B2316Protocol.java index 582be0b56..e0a6821d8 100644 --- a/src/main/java/org/traccar/protocol/B2316Protocol.java +++ b/src/main/java/org/traccar/protocol/B2316Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class B2316Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java b/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java index 635806b2d..b0a5411f7 100644 --- a/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java @@ -24,9 +24,9 @@ import org.traccar.model.Network; import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.util.Date; diff --git a/src/main/java/org/traccar/protocol/BceProtocol.java b/src/main/java/org/traccar/protocol/BceProtocol.java index 31fb1bd83..5e1c10abc 100644 --- a/src/main/java/org/traccar/protocol/BceProtocol.java +++ b/src/main/java/org/traccar/protocol/BceProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BceProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java index 3859a9273..d584af5a1 100644 --- a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java +++ b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BlackKiteProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BlueProtocol.java b/src/main/java/org/traccar/protocol/BlueProtocol.java index da195f438..821111ad7 100644 --- a/src/main/java/org/traccar/protocol/BlueProtocol.java +++ b/src/main/java/org/traccar/protocol/BlueProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BlueProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BoxProtocol.java b/src/main/java/org/traccar/protocol/BoxProtocol.java index dc6852d50..ac1ba7cae 100644 --- a/src/main/java/org/traccar/protocol/BoxProtocol.java +++ b/src/main/java/org/traccar/protocol/BoxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BoxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BstplProtocol.java b/src/main/java/org/traccar/protocol/BstplProtocol.java index dde14a2ca..ccedcf3d9 100644 --- a/src/main/java/org/traccar/protocol/BstplProtocol.java +++ b/src/main/java/org/traccar/protocol/BstplProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BstplProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/C2stekProtocol.java b/src/main/java/org/traccar/protocol/C2stekProtocol.java index 5cd8ef4fd..5370ea762 100644 --- a/src/main/java/org/traccar/protocol/C2stekProtocol.java +++ b/src/main/java/org/traccar/protocol/C2stekProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class C2stekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CalAmpProtocol.java b/src/main/java/org/traccar/protocol/CalAmpProtocol.java index d67308cf2..06df6e196 100644 --- a/src/main/java/org/traccar/protocol/CalAmpProtocol.java +++ b/src/main/java/org/traccar/protocol/CalAmpProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CalAmpProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CarTrackProtocol.java b/src/main/java/org/traccar/protocol/CarTrackProtocol.java index 0538aad72..366f32034 100644 --- a/src/main/java/org/traccar/protocol/CarTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/CarTrackProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CarTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CarcellProtocol.java b/src/main/java/org/traccar/protocol/CarcellProtocol.java index 832d9bb2d..7ae8159d5 100644 --- a/src/main/java/org/traccar/protocol/CarcellProtocol.java +++ b/src/main/java/org/traccar/protocol/CarcellProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CarcellProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CarscopProtocol.java b/src/main/java/org/traccar/protocol/CarscopProtocol.java index a4413af28..e904c01c5 100644 --- a/src/main/java/org/traccar/protocol/CarscopProtocol.java +++ b/src/main/java/org/traccar/protocol/CarscopProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CarscopProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CastelProtocol.java b/src/main/java/org/traccar/protocol/CastelProtocol.java index 9323b1503..74a9e9ca1 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocol.java +++ b/src/main/java/org/traccar/protocol/CastelProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import org.traccar.model.Command; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CastelProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CautelaProtocol.java b/src/main/java/org/traccar/protocol/CautelaProtocol.java index d0ca35ef1..067345f49 100644 --- a/src/main/java/org/traccar/protocol/CautelaProtocol.java +++ b/src/main/java/org/traccar/protocol/CautelaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CautelaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocol.java b/src/main/java/org/traccar/protocol/CellocatorProtocol.java index 3287928c7..e3325c8b7 100644 --- a/src/main/java/org/traccar/protocol/CellocatorProtocol.java +++ b/src/main/java/org/traccar/protocol/CellocatorProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CellocatorProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CguardProtocol.java b/src/main/java/org/traccar/protocol/CguardProtocol.java index caf0aad42..c0fc9582a 100644 --- a/src/main/java/org/traccar/protocol/CguardProtocol.java +++ b/src/main/java/org/traccar/protocol/CguardProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CguardProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocol.java b/src/main/java/org/traccar/protocol/CityeasyProtocol.java index 9656b284b..60ed5d135 100644 --- a/src/main/java/org/traccar/protocol/CityeasyProtocol.java +++ b/src/main/java/org/traccar/protocol/CityeasyProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CityeasyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ContinentalProtocol.java b/src/main/java/org/traccar/protocol/ContinentalProtocol.java index 06e93d79d..9567374fd 100644 --- a/src/main/java/org/traccar/protocol/ContinentalProtocol.java +++ b/src/main/java/org/traccar/protocol/ContinentalProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ContinentalProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CradlepointProtocol.java b/src/main/java/org/traccar/protocol/CradlepointProtocol.java index 7f201a31d..220db0747 100644 --- a/src/main/java/org/traccar/protocol/CradlepointProtocol.java +++ b/src/main/java/org/traccar/protocol/CradlepointProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CradlepointProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DingtekProtocol.java b/src/main/java/org/traccar/protocol/DingtekProtocol.java index e9466b7e8..ab3e32fdb 100644 --- a/src/main/java/org/traccar/protocol/DingtekProtocol.java +++ b/src/main/java/org/traccar/protocol/DingtekProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DingtekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DishaProtocol.java b/src/main/java/org/traccar/protocol/DishaProtocol.java index f83b8349a..0a582731d 100644 --- a/src/main/java/org/traccar/protocol/DishaProtocol.java +++ b/src/main/java/org/traccar/protocol/DishaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DishaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocol.java b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java index 0dab26cda..d15bfa1ca 100644 --- a/src/main/java/org/traccar/protocol/DmtHttpProtocol.java +++ b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DmtHttpProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java index 807850778..c2e617a2a 100644 --- a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java @@ -25,9 +25,9 @@ import org.traccar.helper.BitUtil; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/DmtProtocol.java b/src/main/java/org/traccar/protocol/DmtProtocol.java index de56c9372..e89920cd3 100644 --- a/src/main/java/org/traccar/protocol/DmtProtocol.java +++ b/src/main/java/org/traccar/protocol/DmtProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DmtProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DolphinProtocol.java b/src/main/java/org/traccar/protocol/DolphinProtocol.java index ed627be78..e2acce7dd 100644 --- a/src/main/java/org/traccar/protocol/DolphinProtocol.java +++ b/src/main/java/org/traccar/protocol/DolphinProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DolphinProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Dsf22Protocol.java b/src/main/java/org/traccar/protocol/Dsf22Protocol.java index 06c99b0f9..ad349a7ff 100644 --- a/src/main/java/org/traccar/protocol/Dsf22Protocol.java +++ b/src/main/java/org/traccar/protocol/Dsf22Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Dsf22Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DualcamProtocol.java b/src/main/java/org/traccar/protocol/DualcamProtocol.java index 363a2c5d9..4725cb180 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocol.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DualcamProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DwayProtocol.java b/src/main/java/org/traccar/protocol/DwayProtocol.java index 1096c945c..2ba1cf5f1 100644 --- a/src/main/java/org/traccar/protocol/DwayProtocol.java +++ b/src/main/java/org/traccar/protocol/DwayProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DwayProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocol.java b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java index 39aa61580..25d4ef9a0 100644 --- a/src/main/java/org/traccar/protocol/EasyTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EasyTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EelinkProtocol.java b/src/main/java/org/traccar/protocol/EelinkProtocol.java index 35fd4fe65..2a3c0bd15 100644 --- a/src/main/java/org/traccar/protocol/EelinkProtocol.java +++ b/src/main/java/org/traccar/protocol/EelinkProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EelinkProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EgtsProtocol.java b/src/main/java/org/traccar/protocol/EgtsProtocol.java index f257271d4..5450d9f01 100644 --- a/src/main/java/org/traccar/protocol/EgtsProtocol.java +++ b/src/main/java/org/traccar/protocol/EgtsProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EgtsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EnforaProtocol.java b/src/main/java/org/traccar/protocol/EnforaProtocol.java index ebde56f70..3b796db25 100644 --- a/src/main/java/org/traccar/protocol/EnforaProtocol.java +++ b/src/main/java/org/traccar/protocol/EnforaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EnforaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EnnfuProtocol.java b/src/main/java/org/traccar/protocol/EnnfuProtocol.java index e326481fa..a3ff943fa 100644 --- a/src/main/java/org/traccar/protocol/EnnfuProtocol.java +++ b/src/main/java/org/traccar/protocol/EnnfuProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EnnfuProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EnvotechProtocol.java b/src/main/java/org/traccar/protocol/EnvotechProtocol.java index dffa1c991..e432ac07c 100644 --- a/src/main/java/org/traccar/protocol/EnvotechProtocol.java +++ b/src/main/java/org/traccar/protocol/EnvotechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EnvotechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EsealProtocol.java b/src/main/java/org/traccar/protocol/EsealProtocol.java index 0ed80dc6f..eae4cf2aa 100644 --- a/src/main/java/org/traccar/protocol/EsealProtocol.java +++ b/src/main/java/org/traccar/protocol/EsealProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EsealProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EskyProtocol.java b/src/main/java/org/traccar/protocol/EskyProtocol.java index cb2f59dc8..002e268ba 100644 --- a/src/main/java/org/traccar/protocol/EskyProtocol.java +++ b/src/main/java/org/traccar/protocol/EskyProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EskyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ExtremTracProtocol.java b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java index ffc941b69..23a993fe4 100644 --- a/src/main/java/org/traccar/protocol/ExtremTracProtocol.java +++ b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ExtremTracProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocol.java b/src/main/java/org/traccar/protocol/FifotrackProtocol.java index fd2beaabb..e98ad84cc 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocol.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FifotrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlespiProtocol.java b/src/main/java/org/traccar/protocol/FlespiProtocol.java index 374cf77e2..0d8448845 100644 --- a/src/main/java/org/traccar/protocol/FlespiProtocol.java +++ b/src/main/java/org/traccar/protocol/FlespiProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlespiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java index 95d491af7..ea076afd8 100644 --- a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java @@ -24,12 +24,12 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonNumber; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/FlexApiProtocol.java b/src/main/java/org/traccar/protocol/FlexApiProtocol.java index 088072d2d..b2e3f5d00 100644 --- a/src/main/java/org/traccar/protocol/FlexApiProtocol.java +++ b/src/main/java/org/traccar/protocol/FlexApiProtocol.java @@ -24,7 +24,7 @@ import org.traccar.config.Config; import java.nio.charset.StandardCharsets; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlexApiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java index 2dec44e64..fb76673ca 100644 --- a/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java @@ -23,8 +23,8 @@ import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.util.Date; diff --git a/src/main/java/org/traccar/protocol/FlexCommProtocol.java b/src/main/java/org/traccar/protocol/FlexCommProtocol.java index 5397156cb..293b9b12b 100644 --- a/src/main/java/org/traccar/protocol/FlexCommProtocol.java +++ b/src/main/java/org/traccar/protocol/FlexCommProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlexCommProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java b/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java index 61e315af9..a16e61458 100644 --- a/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java +++ b/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlexibleReportProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlextrackProtocol.java b/src/main/java/org/traccar/protocol/FlextrackProtocol.java index ebac8b4de..b6353de9d 100644 --- a/src/main/java/org/traccar/protocol/FlextrackProtocol.java +++ b/src/main/java/org/traccar/protocol/FlextrackProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlextrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FoxProtocol.java b/src/main/java/org/traccar/protocol/FoxProtocol.java index fa45b3817..edb496f11 100644 --- a/src/main/java/org/traccar/protocol/FoxProtocol.java +++ b/src/main/java/org/traccar/protocol/FoxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FoxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FreedomProtocol.java b/src/main/java/org/traccar/protocol/FreedomProtocol.java index dac117c04..87404094a 100644 --- a/src/main/java/org/traccar/protocol/FreedomProtocol.java +++ b/src/main/java/org/traccar/protocol/FreedomProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FreedomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocol.java b/src/main/java/org/traccar/protocol/FreematicsProtocol.java index dce4994ab..c4076f330 100644 --- a/src/main/java/org/traccar/protocol/FreematicsProtocol.java +++ b/src/main/java/org/traccar/protocol/FreematicsProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FreematicsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FutureWayProtocol.java b/src/main/java/org/traccar/protocol/FutureWayProtocol.java index 715dd3c9c..20586bede 100644 --- a/src/main/java/org/traccar/protocol/FutureWayProtocol.java +++ b/src/main/java/org/traccar/protocol/FutureWayProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FutureWayProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/G1rusProtocol.java b/src/main/java/org/traccar/protocol/G1rusProtocol.java index f1823762d..b3904b357 100644 --- a/src/main/java/org/traccar/protocol/G1rusProtocol.java +++ b/src/main/java/org/traccar/protocol/G1rusProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class G1rusProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GalileoProtocol.java b/src/main/java/org/traccar/protocol/GalileoProtocol.java index 90e95574a..95ce4edde 100644 --- a/src/main/java/org/traccar/protocol/GalileoProtocol.java +++ b/src/main/java/org/traccar/protocol/GalileoProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GalileoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index 46862f583..c961093ab 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GatorProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GenxProtocol.java b/src/main/java/org/traccar/protocol/GenxProtocol.java index 97d8633a0..7e5a6a69e 100644 --- a/src/main/java/org/traccar/protocol/GenxProtocol.java +++ b/src/main/java/org/traccar/protocol/GenxProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GenxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gl100Protocol.java b/src/main/java/org/traccar/protocol/Gl100Protocol.java index e1748c9a0..fdd79648f 100644 --- a/src/main/java/org/traccar/protocol/Gl100Protocol.java +++ b/src/main/java/org/traccar/protocol/Gl100Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gl100Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gl200Protocol.java b/src/main/java/org/traccar/protocol/Gl200Protocol.java index c7b6a8e7c..e3ddbb46e 100644 --- a/src/main/java/org/traccar/protocol/Gl200Protocol.java +++ b/src/main/java/org/traccar/protocol/Gl200Protocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gl200Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java index a9736c9e7..9b4e05c35 100644 --- a/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java @@ -22,7 +22,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import org.traccar.Protocol; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.net.SocketAddress; public class Gl200ProtocolDecoder extends BaseProtocolDecoder { diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java index 16b99f426..13f4f2646 100644 --- a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java +++ b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GlobalSatProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocol.java b/src/main/java/org/traccar/protocol/GlobalstarProtocol.java index 293f5fda5..1d9b6b6dd 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocol.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GlobalstarProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GnxProtocol.java b/src/main/java/org/traccar/protocol/GnxProtocol.java index 32d642688..cfa496009 100644 --- a/src/main/java/org/traccar/protocol/GnxProtocol.java +++ b/src/main/java/org/traccar/protocol/GnxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GnxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocol.java b/src/main/java/org/traccar/protocol/GoSafeProtocol.java index 607931500..c9c0456a0 100644 --- a/src/main/java/org/traccar/protocol/GoSafeProtocol.java +++ b/src/main/java/org/traccar/protocol/GoSafeProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GoSafeProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GotopProtocol.java b/src/main/java/org/traccar/protocol/GotopProtocol.java index 53fcea0d0..21fbbae99 100644 --- a/src/main/java/org/traccar/protocol/GotopProtocol.java +++ b/src/main/java/org/traccar/protocol/GotopProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GotopProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gps056Protocol.java b/src/main/java/org/traccar/protocol/Gps056Protocol.java index dbffbfdbb..44fc392be 100644 --- a/src/main/java/org/traccar/protocol/Gps056Protocol.java +++ b/src/main/java/org/traccar/protocol/Gps056Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gps056Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gps103Protocol.java b/src/main/java/org/traccar/protocol/Gps103Protocol.java index 2725494c5..8424abfe5 100644 --- a/src/main/java/org/traccar/protocol/Gps103Protocol.java +++ b/src/main/java/org/traccar/protocol/Gps103Protocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gps103Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GpsGateProtocol.java b/src/main/java/org/traccar/protocol/GpsGateProtocol.java index a6a73ae6b..db1e8554a 100644 --- a/src/main/java/org/traccar/protocol/GpsGateProtocol.java +++ b/src/main/java/org/traccar/protocol/GpsGateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GpsGateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java index 12b53342c..f50088b2b 100644 --- a/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java +++ b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GpsMarkerProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GpsmtaProtocol.java b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java index a474b1e53..e146a816d 100644 --- a/src/main/java/org/traccar/protocol/GpsmtaProtocol.java +++ b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GpsmtaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GranitProtocol.java b/src/main/java/org/traccar/protocol/GranitProtocol.java index bb66501e2..9ca0fe25e 100644 --- a/src/main/java/org/traccar/protocol/GranitProtocol.java +++ b/src/main/java/org/traccar/protocol/GranitProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GranitProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gs100Protocol.java b/src/main/java/org/traccar/protocol/Gs100Protocol.java index 425ca9330..715d48fc4 100644 --- a/src/main/java/org/traccar/protocol/Gs100Protocol.java +++ b/src/main/java/org/traccar/protocol/Gs100Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gs100Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gt02Protocol.java b/src/main/java/org/traccar/protocol/Gt02Protocol.java index fa05761f6..f448feacc 100644 --- a/src/main/java/org/traccar/protocol/Gt02Protocol.java +++ b/src/main/java/org/traccar/protocol/Gt02Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gt02Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gt06Protocol.java b/src/main/java/org/traccar/protocol/Gt06Protocol.java index 38278121c..945ec3831 100644 --- a/src/main/java/org/traccar/protocol/Gt06Protocol.java +++ b/src/main/java/org/traccar/protocol/Gt06Protocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gt06Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gt30Protocol.java b/src/main/java/org/traccar/protocol/Gt30Protocol.java index 6b79ba58b..fdfc80502 100644 --- a/src/main/java/org/traccar/protocol/Gt30Protocol.java +++ b/src/main/java/org/traccar/protocol/Gt30Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gt30Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/H02Protocol.java b/src/main/java/org/traccar/protocol/H02Protocol.java index 4e5f8c96a..ba5aeaa26 100644 --- a/src/main/java/org/traccar/protocol/H02Protocol.java +++ b/src/main/java/org/traccar/protocol/H02Protocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class H02Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HaicomProtocol.java b/src/main/java/org/traccar/protocol/HaicomProtocol.java index f56c605f0..bcc491ada 100644 --- a/src/main/java/org/traccar/protocol/HaicomProtocol.java +++ b/src/main/java/org/traccar/protocol/HaicomProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HaicomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HomtecsProtocol.java b/src/main/java/org/traccar/protocol/HomtecsProtocol.java index aa2d7d852..c04efb945 100644 --- a/src/main/java/org/traccar/protocol/HomtecsProtocol.java +++ b/src/main/java/org/traccar/protocol/HomtecsProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HomtecsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HoopoProtocol.java b/src/main/java/org/traccar/protocol/HoopoProtocol.java index 02d8e5a8e..3fc0887d8 100644 --- a/src/main/java/org/traccar/protocol/HoopoProtocol.java +++ b/src/main/java/org/traccar/protocol/HoopoProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HoopoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java index 708c74f2a..7433e7fce 100644 --- a/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java @@ -21,8 +21,8 @@ import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.time.OffsetDateTime; diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocol.java b/src/main/java/org/traccar/protocol/HuaShengProtocol.java index 1f8bafc57..7246e97e6 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocol.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HuaShengProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocol.java b/src/main/java/org/traccar/protocol/HuabaoProtocol.java index c37918b0e..fc12d7d71 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocol.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HuabaoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HunterProProtocol.java b/src/main/java/org/traccar/protocol/HunterProProtocol.java index ed4289d73..64dab33b1 100644 --- a/src/main/java/org/traccar/protocol/HunterProProtocol.java +++ b/src/main/java/org/traccar/protocol/HunterProProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HunterProProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/IdplProtocol.java b/src/main/java/org/traccar/protocol/IdplProtocol.java index aa1f4ff5b..1e44ad74c 100644 --- a/src/main/java/org/traccar/protocol/IdplProtocol.java +++ b/src/main/java/org/traccar/protocol/IdplProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class IdplProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/IntellitracProtocol.java b/src/main/java/org/traccar/protocol/IntellitracProtocol.java index b1a91cca9..a82e6a5db 100644 --- a/src/main/java/org/traccar/protocol/IntellitracProtocol.java +++ b/src/main/java/org/traccar/protocol/IntellitracProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class IntellitracProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/IotmProtocol.java b/src/main/java/org/traccar/protocol/IotmProtocol.java index 0d288f4bf..1631b67d8 100644 --- a/src/main/java/org/traccar/protocol/IotmProtocol.java +++ b/src/main/java/org/traccar/protocol/IotmProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class IotmProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ItsProtocol.java b/src/main/java/org/traccar/protocol/ItsProtocol.java index 5148e8ab0..7d59ea60c 100644 --- a/src/main/java/org/traccar/protocol/ItsProtocol.java +++ b/src/main/java/org/traccar/protocol/ItsProtocol.java @@ -23,7 +23,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ItsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Ivt401Protocol.java b/src/main/java/org/traccar/protocol/Ivt401Protocol.java index 763457641..5132c7467 100644 --- a/src/main/java/org/traccar/protocol/Ivt401Protocol.java +++ b/src/main/java/org/traccar/protocol/Ivt401Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Ivt401Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/JidoProtocol.java b/src/main/java/org/traccar/protocol/JidoProtocol.java index 78aa6c81c..b30cc586a 100644 --- a/src/main/java/org/traccar/protocol/JidoProtocol.java +++ b/src/main/java/org/traccar/protocol/JidoProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class JidoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java index 30c8e9977..ae312ea3e 100644 --- a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java +++ b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class JpKorjarProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Jt600Protocol.java b/src/main/java/org/traccar/protocol/Jt600Protocol.java index bf0b3379e..9dc62662f 100644 --- a/src/main/java/org/traccar/protocol/Jt600Protocol.java +++ b/src/main/java/org/traccar/protocol/Jt600Protocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Jt600Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/KenjiProtocol.java b/src/main/java/org/traccar/protocol/KenjiProtocol.java index 8d78c8c56..b4e610cbd 100644 --- a/src/main/java/org/traccar/protocol/KenjiProtocol.java +++ b/src/main/java/org/traccar/protocol/KenjiProtocol.java @@ -24,7 +24,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class KenjiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/KhdProtocol.java b/src/main/java/org/traccar/protocol/KhdProtocol.java index 521274de5..add13ef16 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocol.java +++ b/src/main/java/org/traccar/protocol/KhdProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class KhdProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/L100Protocol.java b/src/main/java/org/traccar/protocol/L100Protocol.java index 0edea6095..fa6d1b07e 100644 --- a/src/main/java/org/traccar/protocol/L100Protocol.java +++ b/src/main/java/org/traccar/protocol/L100Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class L100Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/LacakProtocol.java b/src/main/java/org/traccar/protocol/LacakProtocol.java index bbebd51ed..ddaf5078d 100644 --- a/src/main/java/org/traccar/protocol/LacakProtocol.java +++ b/src/main/java/org/traccar/protocol/LacakProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class LacakProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java b/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java index 809fafc90..66aab3490 100644 --- a/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java @@ -24,8 +24,8 @@ import org.traccar.Protocol; import org.traccar.helper.DateUtil; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java index 249d3bcbe..65b1a57e9 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocol.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class LaipacProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocol.java b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java index 7e13e23d0..9e167e7ba 100644 --- a/src/main/java/org/traccar/protocol/LeafSpyProtocol.java +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java @@ -24,7 +24,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class LeafSpyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/M2cProtocol.java b/src/main/java/org/traccar/protocol/M2cProtocol.java index a23ea0f57..8abc30f60 100644 --- a/src/main/java/org/traccar/protocol/M2cProtocol.java +++ b/src/main/java/org/traccar/protocol/M2cProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class M2cProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/M2mProtocol.java b/src/main/java/org/traccar/protocol/M2mProtocol.java index 6809d800c..03a069d66 100644 --- a/src/main/java/org/traccar/protocol/M2mProtocol.java +++ b/src/main/java/org/traccar/protocol/M2mProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class M2mProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MaestroProtocol.java b/src/main/java/org/traccar/protocol/MaestroProtocol.java index 38a67f9a4..29f0b8897 100644 --- a/src/main/java/org/traccar/protocol/MaestroProtocol.java +++ b/src/main/java/org/traccar/protocol/MaestroProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MaestroProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ManPowerProtocol.java b/src/main/java/org/traccar/protocol/ManPowerProtocol.java index 492e86605..ba2414ca7 100644 --- a/src/main/java/org/traccar/protocol/ManPowerProtocol.java +++ b/src/main/java/org/traccar/protocol/ManPowerProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ManPowerProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Mavlink2Protocol.java b/src/main/java/org/traccar/protocol/Mavlink2Protocol.java index cf65a2db3..916fb7467 100644 --- a/src/main/java/org/traccar/protocol/Mavlink2Protocol.java +++ b/src/main/java/org/traccar/protocol/Mavlink2Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Mavlink2Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MegastekProtocol.java b/src/main/java/org/traccar/protocol/MegastekProtocol.java index 10215eb7c..9f8937f01 100644 --- a/src/main/java/org/traccar/protocol/MegastekProtocol.java +++ b/src/main/java/org/traccar/protocol/MegastekProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MegastekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java index 492094ce3..d86a00fb3 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MeiligaoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocol.java b/src/main/java/org/traccar/protocol/MeitrackProtocol.java index c6eba8fe1..4109b22c9 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocol.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MeitrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MictrackProtocol.java b/src/main/java/org/traccar/protocol/MictrackProtocol.java index ccbc4db4c..08bbe0c82 100644 --- a/src/main/java/org/traccar/protocol/MictrackProtocol.java +++ b/src/main/java/org/traccar/protocol/MictrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MictrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MilesmateProtocol.java b/src/main/java/org/traccar/protocol/MilesmateProtocol.java index 59212e791..607dfc5bf 100644 --- a/src/main/java/org/traccar/protocol/MilesmateProtocol.java +++ b/src/main/java/org/traccar/protocol/MilesmateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MilesmateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java index 44599accc..1cb2a0007 100644 --- a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MiniFinderProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java index 842194235..c12933b81 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java +++ b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java @@ -24,7 +24,7 @@ import org.traccar.model.Command; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Minifinder2Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MobilogixProtocol.java b/src/main/java/org/traccar/protocol/MobilogixProtocol.java index 1b06c2249..36d6b5ed2 100644 --- a/src/main/java/org/traccar/protocol/MobilogixProtocol.java +++ b/src/main/java/org/traccar/protocol/MobilogixProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MobilogixProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MoovboxProtocol.java b/src/main/java/org/traccar/protocol/MoovboxProtocol.java index 16438e122..af853fe67 100644 --- a/src/main/java/org/traccar/protocol/MoovboxProtocol.java +++ b/src/main/java/org/traccar/protocol/MoovboxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MoovboxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MotorProtocol.java b/src/main/java/org/traccar/protocol/MotorProtocol.java index 3101c9b75..f17886577 100644 --- a/src/main/java/org/traccar/protocol/MotorProtocol.java +++ b/src/main/java/org/traccar/protocol/MotorProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MotorProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Mta6Protocol.java b/src/main/java/org/traccar/protocol/Mta6Protocol.java index 019fe4fa9..c1c6eb829 100644 --- a/src/main/java/org/traccar/protocol/Mta6Protocol.java +++ b/src/main/java/org/traccar/protocol/Mta6Protocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Mta6Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MtxProtocol.java b/src/main/java/org/traccar/protocol/MtxProtocol.java index e085b6221..12d324019 100644 --- a/src/main/java/org/traccar/protocol/MtxProtocol.java +++ b/src/main/java/org/traccar/protocol/MtxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MtxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MxtProtocol.java b/src/main/java/org/traccar/protocol/MxtProtocol.java index 1190bf527..2f0cc1658 100644 --- a/src/main/java/org/traccar/protocol/MxtProtocol.java +++ b/src/main/java/org/traccar/protocol/MxtProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MxtProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavigilProtocol.java b/src/main/java/org/traccar/protocol/NavigilProtocol.java index 46a6c33a5..a309235c5 100644 --- a/src/main/java/org/traccar/protocol/NavigilProtocol.java +++ b/src/main/java/org/traccar/protocol/NavigilProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavigilProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavisProtocol.java b/src/main/java/org/traccar/protocol/NavisProtocol.java index 640a77803..96b5b0de0 100644 --- a/src/main/java/org/traccar/protocol/NavisProtocol.java +++ b/src/main/java/org/traccar/protocol/NavisProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavisProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavisetProtocol.java b/src/main/java/org/traccar/protocol/NavisetProtocol.java index 388f141f8..6df0b0436 100644 --- a/src/main/java/org/traccar/protocol/NavisetProtocol.java +++ b/src/main/java/org/traccar/protocol/NavisetProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavisetProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java index 50013d1a4..de5f93df1 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavtelecomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NdtpV6Protocol.java b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java index ce0dbbef2..9493132f5 100644 --- a/src/main/java/org/traccar/protocol/NdtpV6Protocol.java +++ b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NdtpV6Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NeosProtocol.java b/src/main/java/org/traccar/protocol/NeosProtocol.java index 0787b6562..16a6ba5a0 100644 --- a/src/main/java/org/traccar/protocol/NeosProtocol.java +++ b/src/main/java/org/traccar/protocol/NeosProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NeosProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NetProtocol.java b/src/main/java/org/traccar/protocol/NetProtocol.java index f27e4afb8..e011660da 100644 --- a/src/main/java/org/traccar/protocol/NetProtocol.java +++ b/src/main/java/org/traccar/protocol/NetProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NetProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NiotProtocol.java b/src/main/java/org/traccar/protocol/NiotProtocol.java index 0fbe0c689..7eacd5ff3 100644 --- a/src/main/java/org/traccar/protocol/NiotProtocol.java +++ b/src/main/java/org/traccar/protocol/NiotProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NiotProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NoranProtocol.java b/src/main/java/org/traccar/protocol/NoranProtocol.java index 626991029..d03e52be5 100644 --- a/src/main/java/org/traccar/protocol/NoranProtocol.java +++ b/src/main/java/org/traccar/protocol/NoranProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NoranProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NvsProtocol.java b/src/main/java/org/traccar/protocol/NvsProtocol.java index 7ed488e38..8a4ece30d 100644 --- a/src/main/java/org/traccar/protocol/NvsProtocol.java +++ b/src/main/java/org/traccar/protocol/NvsProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NvsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NyitechProtocol.java b/src/main/java/org/traccar/protocol/NyitechProtocol.java index e7ef10945..225b1bd5a 100644 --- a/src/main/java/org/traccar/protocol/NyitechProtocol.java +++ b/src/main/java/org/traccar/protocol/NyitechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NyitechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ObdDongleProtocol.java b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java index 94f450426..9fcc35d0d 100644 --- a/src/main/java/org/traccar/protocol/ObdDongleProtocol.java +++ b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ObdDongleProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OigoProtocol.java b/src/main/java/org/traccar/protocol/OigoProtocol.java index 0539bada6..3483f8270 100644 --- a/src/main/java/org/traccar/protocol/OigoProtocol.java +++ b/src/main/java/org/traccar/protocol/OigoProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OigoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OkoProtocol.java b/src/main/java/org/traccar/protocol/OkoProtocol.java index 29c8bc1b9..6ca6c0e93 100644 --- a/src/main/java/org/traccar/protocol/OkoProtocol.java +++ b/src/main/java/org/traccar/protocol/OkoProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OkoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OmnicommProtocol.java b/src/main/java/org/traccar/protocol/OmnicommProtocol.java index dd400c779..b59b84132 100644 --- a/src/main/java/org/traccar/protocol/OmnicommProtocol.java +++ b/src/main/java/org/traccar/protocol/OmnicommProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OmnicommProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OpenGtsProtocol.java b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java index 5443b4ffc..24d6de706 100644 --- a/src/main/java/org/traccar/protocol/OpenGtsProtocol.java +++ b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OpenGtsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocol.java b/src/main/java/org/traccar/protocol/OrbcommProtocol.java index fb09f0abb..06b00619c 100644 --- a/src/main/java/org/traccar/protocol/OrbcommProtocol.java +++ b/src/main/java/org/traccar/protocol/OrbcommProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerClient; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OrbcommProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java index 1164d72a1..7ed13d647 100644 --- a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java @@ -24,10 +24,10 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/OrionProtocol.java b/src/main/java/org/traccar/protocol/OrionProtocol.java index 2dec7cd06..b78af462b 100644 --- a/src/main/java/org/traccar/protocol/OrionProtocol.java +++ b/src/main/java/org/traccar/protocol/OrionProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OrionProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocol.java b/src/main/java/org/traccar/protocol/OsmAndProtocol.java index a86bc70d7..e06580949 100644 --- a/src/main/java/org/traccar/protocol/OsmAndProtocol.java +++ b/src/main/java/org/traccar/protocol/OsmAndProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OsmAndProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocol.java b/src/main/java/org/traccar/protocol/OutsafeProtocol.java index 0099be456..159534883 100644 --- a/src/main/java/org/traccar/protocol/OutsafeProtocol.java +++ b/src/main/java/org/traccar/protocol/OutsafeProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OutsafeProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java index 62b873be7..f71778412 100644 --- a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java @@ -23,11 +23,11 @@ import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonNumber; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java index 9ad337f19..c509ad282 100644 --- a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java +++ b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java @@ -24,7 +24,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OwnTracksProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java index 71ac87168..e54d07fa7 100644 --- a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java @@ -25,8 +25,8 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java index 709729ef1..a315d4d9f 100644 --- a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PacificTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PathAwayProtocol.java b/src/main/java/org/traccar/protocol/PathAwayProtocol.java index 1d13eea95..a65740475 100644 --- a/src/main/java/org/traccar/protocol/PathAwayProtocol.java +++ b/src/main/java/org/traccar/protocol/PathAwayProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PathAwayProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocol.java b/src/main/java/org/traccar/protocol/PiligrimProtocol.java index aa45a0def..9dd1bc491 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocol.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PiligrimProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PluginProtocol.java b/src/main/java/org/traccar/protocol/PluginProtocol.java index b2101b18d..fff1830e8 100644 --- a/src/main/java/org/traccar/protocol/PluginProtocol.java +++ b/src/main/java/org/traccar/protocol/PluginProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PluginProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PolteProtocol.java b/src/main/java/org/traccar/protocol/PolteProtocol.java index 69666cc0e..0fbedfb09 100644 --- a/src/main/java/org/traccar/protocol/PolteProtocol.java +++ b/src/main/java/org/traccar/protocol/PolteProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PolteProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java index 028de5424..8954db491 100644 --- a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java @@ -23,8 +23,8 @@ import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/PortmanProtocol.java b/src/main/java/org/traccar/protocol/PortmanProtocol.java index de78013fa..3a4b49289 100644 --- a/src/main/java/org/traccar/protocol/PortmanProtocol.java +++ b/src/main/java/org/traccar/protocol/PortmanProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PortmanProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PretraceProtocol.java b/src/main/java/org/traccar/protocol/PretraceProtocol.java index b77dd97bf..54a34fc69 100644 --- a/src/main/java/org/traccar/protocol/PretraceProtocol.java +++ b/src/main/java/org/traccar/protocol/PretraceProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PretraceProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PricolProtocol.java b/src/main/java/org/traccar/protocol/PricolProtocol.java index f5e904541..7b0e7386c 100644 --- a/src/main/java/org/traccar/protocol/PricolProtocol.java +++ b/src/main/java/org/traccar/protocol/PricolProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PricolProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ProgressProtocol.java b/src/main/java/org/traccar/protocol/ProgressProtocol.java index 49eb6847f..8d159ef24 100644 --- a/src/main/java/org/traccar/protocol/ProgressProtocol.java +++ b/src/main/java/org/traccar/protocol/ProgressProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ProgressProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PstProtocol.java b/src/main/java/org/traccar/protocol/PstProtocol.java index 73f978cbd..01a83b31f 100644 --- a/src/main/java/org/traccar/protocol/PstProtocol.java +++ b/src/main/java/org/traccar/protocol/PstProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PstProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt215Protocol.java b/src/main/java/org/traccar/protocol/Pt215Protocol.java index b272582a4..fd67b1241 100644 --- a/src/main/java/org/traccar/protocol/Pt215Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt215Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt215Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt3000Protocol.java b/src/main/java/org/traccar/protocol/Pt3000Protocol.java index d72774f47..5f49084ed 100644 --- a/src/main/java/org/traccar/protocol/Pt3000Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt3000Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt3000Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt502Protocol.java b/src/main/java/org/traccar/protocol/Pt502Protocol.java index d5d30e8e8..0257dd60f 100644 --- a/src/main/java/org/traccar/protocol/Pt502Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt502Protocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt502Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt60Protocol.java b/src/main/java/org/traccar/protocol/Pt60Protocol.java index 58345f025..83e3bfbeb 100644 --- a/src/main/java/org/traccar/protocol/Pt60Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt60Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt60Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/R12wProtocol.java b/src/main/java/org/traccar/protocol/R12wProtocol.java index a406f6306..b5b3eff81 100644 --- a/src/main/java/org/traccar/protocol/R12wProtocol.java +++ b/src/main/java/org/traccar/protocol/R12wProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class R12wProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java index 63ca3476c..6f7340902 100644 --- a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java +++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RaceDynamicsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RadarProtocol.java b/src/main/java/org/traccar/protocol/RadarProtocol.java index 9d88c6d72..8985e0e83 100644 --- a/src/main/java/org/traccar/protocol/RadarProtocol.java +++ b/src/main/java/org/traccar/protocol/RadarProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RadarProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RaveonProtocol.java b/src/main/java/org/traccar/protocol/RaveonProtocol.java index db70396ee..aa1a79219 100644 --- a/src/main/java/org/traccar/protocol/RaveonProtocol.java +++ b/src/main/java/org/traccar/protocol/RaveonProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RaveonProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RecodaProtocol.java b/src/main/java/org/traccar/protocol/RecodaProtocol.java index 0d50db01e..7d2fadae4 100644 --- a/src/main/java/org/traccar/protocol/RecodaProtocol.java +++ b/src/main/java/org/traccar/protocol/RecodaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RecodaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RetranslatorProtocol.java b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java index 1d4b419bb..a349a8191 100644 --- a/src/main/java/org/traccar/protocol/RetranslatorProtocol.java +++ b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RetranslatorProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RfTrackProtocol.java b/src/main/java/org/traccar/protocol/RfTrackProtocol.java index d3b41e93e..ac033c348 100644 --- a/src/main/java/org/traccar/protocol/RfTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/RfTrackProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RfTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java index 28a3ac29c..cbb204e3b 100644 --- a/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java @@ -29,9 +29,9 @@ import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; import org.traccar.session.DeviceSession; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/RitiProtocol.java b/src/main/java/org/traccar/protocol/RitiProtocol.java index 9b9c00cb2..9916042a8 100644 --- a/src/main/java/org/traccar/protocol/RitiProtocol.java +++ b/src/main/java/org/traccar/protocol/RitiProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RitiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RoboTrackProtocol.java b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java index ab2bc5842..229c343bb 100644 --- a/src/main/java/org/traccar/protocol/RoboTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RoboTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RstProtocol.java b/src/main/java/org/traccar/protocol/RstProtocol.java index 109d91b16..0bb809a49 100644 --- a/src/main/java/org/traccar/protocol/RstProtocol.java +++ b/src/main/java/org/traccar/protocol/RstProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RstProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocol.java b/src/main/java/org/traccar/protocol/RuptelaProtocol.java index 99a9686f6..9f399e299 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocol.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RuptelaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/S168Protocol.java b/src/main/java/org/traccar/protocol/S168Protocol.java index f904ed9ff..5fb0c6e72 100644 --- a/src/main/java/org/traccar/protocol/S168Protocol.java +++ b/src/main/java/org/traccar/protocol/S168Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class S168Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SabertekProtocol.java b/src/main/java/org/traccar/protocol/SabertekProtocol.java index 403243cdc..cb3f2ab32 100644 --- a/src/main/java/org/traccar/protocol/SabertekProtocol.java +++ b/src/main/java/org/traccar/protocol/SabertekProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SabertekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SanavProtocol.java b/src/main/java/org/traccar/protocol/SanavProtocol.java index 1a0e7b0e9..ac1941725 100644 --- a/src/main/java/org/traccar/protocol/SanavProtocol.java +++ b/src/main/java/org/traccar/protocol/SanavProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SanavProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SanulProtocol.java b/src/main/java/org/traccar/protocol/SanulProtocol.java index ea44bf868..cba162296 100644 --- a/src/main/java/org/traccar/protocol/SanulProtocol.java +++ b/src/main/java/org/traccar/protocol/SanulProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SanulProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SatsolProtocol.java b/src/main/java/org/traccar/protocol/SatsolProtocol.java index d90033e38..7252f99f0 100644 --- a/src/main/java/org/traccar/protocol/SatsolProtocol.java +++ b/src/main/java/org/traccar/protocol/SatsolProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SatsolProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocol.java b/src/main/java/org/traccar/protocol/SigfoxProtocol.java index 9a268af62..edd624727 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocol.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SigfoxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index 4ed2bb51d..1298112d1 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -32,11 +32,11 @@ import org.traccar.model.Network; import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; -import javax.json.Json; -import javax.json.JsonNumber; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.net.URLDecoder; diff --git a/src/main/java/org/traccar/protocol/SiwiProtocol.java b/src/main/java/org/traccar/protocol/SiwiProtocol.java index f12958a50..59b96bf72 100644 --- a/src/main/java/org/traccar/protocol/SiwiProtocol.java +++ b/src/main/java/org/traccar/protocol/SiwiProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SiwiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SkypatrolProtocol.java b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java index 7ae26f634..615ef536d 100644 --- a/src/main/java/org/traccar/protocol/SkypatrolProtocol.java +++ b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SkypatrolProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SmartSoleProtocol.java b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java index cb7efb7ee..e4838581a 100644 --- a/src/main/java/org/traccar/protocol/SmartSoleProtocol.java +++ b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SmartSoleProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SmokeyProtocol.java b/src/main/java/org/traccar/protocol/SmokeyProtocol.java index 22b343537..0aa2bcfa7 100644 --- a/src/main/java/org/traccar/protocol/SmokeyProtocol.java +++ b/src/main/java/org/traccar/protocol/SmokeyProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SmokeyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java index 0676aa629..e00f27b9b 100644 --- a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java +++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SolarPoweredProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SpotProtocol.java b/src/main/java/org/traccar/protocol/SpotProtocol.java index 6bd802fed..4fc57f177 100644 --- a/src/main/java/org/traccar/protocol/SpotProtocol.java +++ b/src/main/java/org/traccar/protocol/SpotProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SpotProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocol.java b/src/main/java/org/traccar/protocol/StarLinkProtocol.java index d578fa705..6dcd40fbf 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocol.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StarLinkProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StarcomProtocol.java b/src/main/java/org/traccar/protocol/StarcomProtocol.java index 33c3a4776..458220e59 100644 --- a/src/main/java/org/traccar/protocol/StarcomProtocol.java +++ b/src/main/java/org/traccar/protocol/StarcomProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StarcomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StartekProtocol.java b/src/main/java/org/traccar/protocol/StartekProtocol.java index 1b1c93e33..550545345 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocol.java +++ b/src/main/java/org/traccar/protocol/StartekProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StartekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StbProtocol.java b/src/main/java/org/traccar/protocol/StbProtocol.java index af4e0d2c4..0beaed39c 100644 --- a/src/main/java/org/traccar/protocol/StbProtocol.java +++ b/src/main/java/org/traccar/protocol/StbProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StbProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StbProtocolDecoder.java b/src/main/java/org/traccar/protocol/StbProtocolDecoder.java index 641359bfd..c52ab485f 100644 --- a/src/main/java/org/traccar/protocol/StbProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StbProtocolDecoder.java @@ -22,9 +22,9 @@ import org.traccar.Protocol; import org.traccar.model.Position; import org.traccar.session.DeviceSession; -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.util.Date; diff --git a/src/main/java/org/traccar/protocol/Stl060Protocol.java b/src/main/java/org/traccar/protocol/Stl060Protocol.java index 83b5db3bb..ac23ab3ee 100644 --- a/src/main/java/org/traccar/protocol/Stl060Protocol.java +++ b/src/main/java/org/traccar/protocol/Stl060Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Stl060Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java index 4253b761b..0cc5fc75c 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocol.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SuntechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SupermateProtocol.java b/src/main/java/org/traccar/protocol/SupermateProtocol.java index 4290b7126..064f12b4b 100644 --- a/src/main/java/org/traccar/protocol/SupermateProtocol.java +++ b/src/main/java/org/traccar/protocol/SupermateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SupermateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SviasProtocol.java b/src/main/java/org/traccar/protocol/SviasProtocol.java index 7c6624f7c..a903d503c 100644 --- a/src/main/java/org/traccar/protocol/SviasProtocol.java +++ b/src/main/java/org/traccar/protocol/SviasProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SviasProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SwiftechProtocol.java b/src/main/java/org/traccar/protocol/SwiftechProtocol.java index 68cf40d84..d5fa5c5d3 100644 --- a/src/main/java/org/traccar/protocol/SwiftechProtocol.java +++ b/src/main/java/org/traccar/protocol/SwiftechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SwiftechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T55Protocol.java b/src/main/java/org/traccar/protocol/T55Protocol.java index cedac275f..e76959fea 100644 --- a/src/main/java/org/traccar/protocol/T55Protocol.java +++ b/src/main/java/org/traccar/protocol/T55Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class T55Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T57Protocol.java b/src/main/java/org/traccar/protocol/T57Protocol.java index 4bafe8c6d..e6ef4ccc9 100644 --- a/src/main/java/org/traccar/protocol/T57Protocol.java +++ b/src/main/java/org/traccar/protocol/T57Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class T57Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocol.java b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java index 1289fe8e7..22efa38a8 100644 --- a/src/main/java/org/traccar/protocol/T622IridiumProtocol.java +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class T622IridiumProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T800xProtocol.java b/src/main/java/org/traccar/protocol/T800xProtocol.java index 253c3cb73..f50f22a18 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocol.java +++ b/src/main/java/org/traccar/protocol/T800xProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class T800xProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TaipProtocol.java b/src/main/java/org/traccar/protocol/TaipProtocol.java index 943ec98c5..71ab485ca 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocol.java +++ b/src/main/java/org/traccar/protocol/TaipProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TaipProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TechTltProtocol.java b/src/main/java/org/traccar/protocol/TechTltProtocol.java index 191dd9ccc..a4a7460b0 100644 --- a/src/main/java/org/traccar/protocol/TechTltProtocol.java +++ b/src/main/java/org/traccar/protocol/TechTltProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TechTltProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java index 265a3eb64..f0828a99e 100644 --- a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java +++ b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TechtoCruzProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TekProtocol.java b/src/main/java/org/traccar/protocol/TekProtocol.java index 54e860d79..56714041b 100644 --- a/src/main/java/org/traccar/protocol/TekProtocol.java +++ b/src/main/java/org/traccar/protocol/TekProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TelemaxProtocol.java b/src/main/java/org/traccar/protocol/TelemaxProtocol.java index 9e9cbb50e..792a5b176 100644 --- a/src/main/java/org/traccar/protocol/TelemaxProtocol.java +++ b/src/main/java/org/traccar/protocol/TelemaxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TelemaxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TelicProtocol.java b/src/main/java/org/traccar/protocol/TelicProtocol.java index 9ef7864ca..fc5bdf0d1 100644 --- a/src/main/java/org/traccar/protocol/TelicProtocol.java +++ b/src/main/java/org/traccar/protocol/TelicProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TelicProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java index 38283cb64..f2d610251 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TeltonikaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocol.java b/src/main/java/org/traccar/protocol/TeraTrackProtocol.java index 73219cc5e..e872ddf42 100644 --- a/src/main/java/org/traccar/protocol/TeraTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/TeraTrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TeraTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java index 423ae3ffe..be4b98e4c 100644 --- a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java @@ -23,8 +23,8 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.text.DateFormat; diff --git a/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java b/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java index 38bf078aa..b23dadf08 100644 --- a/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java +++ b/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ThinkPowerProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java index 782b0a352..34b80ba87 100644 --- a/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java +++ b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ThinkRaceProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ThurayaProtocol.java b/src/main/java/org/traccar/protocol/ThurayaProtocol.java index f709a1183..33d486f6b 100644 --- a/src/main/java/org/traccar/protocol/ThurayaProtocol.java +++ b/src/main/java/org/traccar/protocol/ThurayaProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ThurayaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tk102Protocol.java b/src/main/java/org/traccar/protocol/Tk102Protocol.java index 150e83ab3..b6a82981b 100644 --- a/src/main/java/org/traccar/protocol/Tk102Protocol.java +++ b/src/main/java/org/traccar/protocol/Tk102Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tk102Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tk103Protocol.java b/src/main/java/org/traccar/protocol/Tk103Protocol.java index cf09886f5..b641ef083 100644 --- a/src/main/java/org/traccar/protocol/Tk103Protocol.java +++ b/src/main/java/org/traccar/protocol/Tk103Protocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tk103Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocol.java b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java index b10271f7d..6763e9b6b 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocol.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tlt2hProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TlvProtocol.java b/src/main/java/org/traccar/protocol/TlvProtocol.java index 9d83388c9..f99676d23 100644 --- a/src/main/java/org/traccar/protocol/TlvProtocol.java +++ b/src/main/java/org/traccar/protocol/TlvProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TlvProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TmgProtocol.java b/src/main/java/org/traccar/protocol/TmgProtocol.java index e078c425b..dbba648be 100644 --- a/src/main/java/org/traccar/protocol/TmgProtocol.java +++ b/src/main/java/org/traccar/protocol/TmgProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TmgProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TopflytechProtocol.java b/src/main/java/org/traccar/protocol/TopflytechProtocol.java index 339d2fc8d..a658235ab 100644 --- a/src/main/java/org/traccar/protocol/TopflytechProtocol.java +++ b/src/main/java/org/traccar/protocol/TopflytechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TopflytechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TopinProtocol.java b/src/main/java/org/traccar/protocol/TopinProtocol.java index 37afac582..1a558f617 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocol.java +++ b/src/main/java/org/traccar/protocol/TopinProtocol.java @@ -22,7 +22,7 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TopinProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TotemProtocol.java b/src/main/java/org/traccar/protocol/TotemProtocol.java index 9ab36fd0b..b02d4f1fc 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocol.java +++ b/src/main/java/org/traccar/protocol/TotemProtocol.java @@ -23,7 +23,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TotemProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tr20Protocol.java b/src/main/java/org/traccar/protocol/Tr20Protocol.java index 615fdab28..3b3fc02b6 100644 --- a/src/main/java/org/traccar/protocol/Tr20Protocol.java +++ b/src/main/java/org/traccar/protocol/Tr20Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tr20Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tr900Protocol.java b/src/main/java/org/traccar/protocol/Tr900Protocol.java index 162cbe651..c5f357604 100644 --- a/src/main/java/org/traccar/protocol/Tr900Protocol.java +++ b/src/main/java/org/traccar/protocol/Tr900Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tr900Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TrackboxProtocol.java b/src/main/java/org/traccar/protocol/TrackboxProtocol.java index 4236144a3..eadcd07f9 100644 --- a/src/main/java/org/traccar/protocol/TrackboxProtocol.java +++ b/src/main/java/org/traccar/protocol/TrackboxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TrackboxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TrakMateProtocol.java b/src/main/java/org/traccar/protocol/TrakMateProtocol.java index b7637e6f3..f4e7c5e60 100644 --- a/src/main/java/org/traccar/protocol/TrakMateProtocol.java +++ b/src/main/java/org/traccar/protocol/TrakMateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TrakMateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TramigoProtocol.java b/src/main/java/org/traccar/protocol/TramigoProtocol.java index 79a59abd3..5d8baf2a9 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocol.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TramigoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java index fcc02a781..fb37a1ab4 100644 --- a/src/main/java/org/traccar/protocol/TranSyncProtocol.java +++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TranSyncProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TrvProtocol.java b/src/main/java/org/traccar/protocol/TrvProtocol.java index e67afbda2..7bdf3d2d0 100644 --- a/src/main/java/org/traccar/protocol/TrvProtocol.java +++ b/src/main/java/org/traccar/protocol/TrvProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TrvProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tt8850Protocol.java b/src/main/java/org/traccar/protocol/Tt8850Protocol.java index ab109e274..8e2800d90 100644 --- a/src/main/java/org/traccar/protocol/Tt8850Protocol.java +++ b/src/main/java/org/traccar/protocol/Tt8850Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tt8850Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TytanProtocol.java b/src/main/java/org/traccar/protocol/TytanProtocol.java index cc3bc9b52..4fd3c807f 100644 --- a/src/main/java/org/traccar/protocol/TytanProtocol.java +++ b/src/main/java/org/traccar/protocol/TytanProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TytanProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TzoneProtocol.java b/src/main/java/org/traccar/protocol/TzoneProtocol.java index d25757b63..2df721049 100644 --- a/src/main/java/org/traccar/protocol/TzoneProtocol.java +++ b/src/main/java/org/traccar/protocol/TzoneProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TzoneProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocol.java b/src/main/java/org/traccar/protocol/UlbotechProtocol.java index 57fc47644..f8c4f1960 100644 --- a/src/main/java/org/traccar/protocol/UlbotechProtocol.java +++ b/src/main/java/org/traccar/protocol/UlbotechProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class UlbotechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/UproProtocol.java b/src/main/java/org/traccar/protocol/UproProtocol.java index e27088594..cbec9777d 100644 --- a/src/main/java/org/traccar/protocol/UproProtocol.java +++ b/src/main/java/org/traccar/protocol/UproProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class UproProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/UuxProtocol.java b/src/main/java/org/traccar/protocol/UuxProtocol.java index 3de4a4732..63727cb94 100644 --- a/src/main/java/org/traccar/protocol/UuxProtocol.java +++ b/src/main/java/org/traccar/protocol/UuxProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class UuxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/V680Protocol.java b/src/main/java/org/traccar/protocol/V680Protocol.java index 53bca849c..587a0c8f7 100644 --- a/src/main/java/org/traccar/protocol/V680Protocol.java +++ b/src/main/java/org/traccar/protocol/V680Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class V680Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/VisiontekProtocol.java b/src/main/java/org/traccar/protocol/VisiontekProtocol.java index 5296402b4..83bcd37ff 100644 --- a/src/main/java/org/traccar/protocol/VisiontekProtocol.java +++ b/src/main/java/org/traccar/protocol/VisiontekProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class VisiontekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/VltProtocol.java b/src/main/java/org/traccar/protocol/VltProtocol.java index ebced83b1..005cd8ffb 100644 --- a/src/main/java/org/traccar/protocol/VltProtocol.java +++ b/src/main/java/org/traccar/protocol/VltProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class VltProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/VnetProtocol.java b/src/main/java/org/traccar/protocol/VnetProtocol.java index dd739f0d9..6ccc54483 100644 --- a/src/main/java/org/traccar/protocol/VnetProtocol.java +++ b/src/main/java/org/traccar/protocol/VnetProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class VnetProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Vt200Protocol.java b/src/main/java/org/traccar/protocol/Vt200Protocol.java index efb5fe2fd..97e64b74f 100644 --- a/src/main/java/org/traccar/protocol/Vt200Protocol.java +++ b/src/main/java/org/traccar/protocol/Vt200Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Vt200Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/VtfmsProtocol.java b/src/main/java/org/traccar/protocol/VtfmsProtocol.java index 482ab4a37..91453c413 100644 --- a/src/main/java/org/traccar/protocol/VtfmsProtocol.java +++ b/src/main/java/org/traccar/protocol/VtfmsProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class VtfmsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WatchProtocol.java b/src/main/java/org/traccar/protocol/WatchProtocol.java index 600f81328..aee70b6ec 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocol.java +++ b/src/main/java/org/traccar/protocol/WatchProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WatchProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WialonProtocol.java b/src/main/java/org/traccar/protocol/WialonProtocol.java index a744349cd..84033132d 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocol.java +++ b/src/main/java/org/traccar/protocol/WialonProtocol.java @@ -27,7 +27,7 @@ import org.traccar.model.Command; import java.nio.charset.StandardCharsets; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WialonProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WliProtocol.java b/src/main/java/org/traccar/protocol/WliProtocol.java index f7084e55b..5b9ebb520 100644 --- a/src/main/java/org/traccar/protocol/WliProtocol.java +++ b/src/main/java/org/traccar/protocol/WliProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WliProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WondexProtocol.java b/src/main/java/org/traccar/protocol/WondexProtocol.java index 5a0401df4..e27b8e2bb 100644 --- a/src/main/java/org/traccar/protocol/WondexProtocol.java +++ b/src/main/java/org/traccar/protocol/WondexProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WondexProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WristbandProtocol.java b/src/main/java/org/traccar/protocol/WristbandProtocol.java index c5d8d4050..117daf8cf 100644 --- a/src/main/java/org/traccar/protocol/WristbandProtocol.java +++ b/src/main/java/org/traccar/protocol/WristbandProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WristbandProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xexun2Protocol.java b/src/main/java/org/traccar/protocol/Xexun2Protocol.java index 52cf731f0..9dd517cfa 100644 --- a/src/main/java/org/traccar/protocol/Xexun2Protocol.java +++ b/src/main/java/org/traccar/protocol/Xexun2Protocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xexun2Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/XexunProtocol.java b/src/main/java/org/traccar/protocol/XexunProtocol.java index 5c7329603..e76e47d19 100644 --- a/src/main/java/org/traccar/protocol/XexunProtocol.java +++ b/src/main/java/org/traccar/protocol/XexunProtocol.java @@ -25,7 +25,7 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class XexunProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/XirgoProtocol.java b/src/main/java/org/traccar/protocol/XirgoProtocol.java index 0841d86d5..7e14c6842 100644 --- a/src/main/java/org/traccar/protocol/XirgoProtocol.java +++ b/src/main/java/org/traccar/protocol/XirgoProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class XirgoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xrb28Protocol.java b/src/main/java/org/traccar/protocol/Xrb28Protocol.java index 65c2a1230..135fb0928 100644 --- a/src/main/java/org/traccar/protocol/Xrb28Protocol.java +++ b/src/main/java/org/traccar/protocol/Xrb28Protocol.java @@ -26,7 +26,7 @@ import org.traccar.model.Command; import java.nio.charset.StandardCharsets; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xrb28Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xt013Protocol.java b/src/main/java/org/traccar/protocol/Xt013Protocol.java index 9e9087609..25809463a 100644 --- a/src/main/java/org/traccar/protocol/Xt013Protocol.java +++ b/src/main/java/org/traccar/protocol/Xt013Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xt013Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xt2400Protocol.java b/src/main/java/org/traccar/protocol/Xt2400Protocol.java index e200adb9f..1b7fc840b 100644 --- a/src/main/java/org/traccar/protocol/Xt2400Protocol.java +++ b/src/main/java/org/traccar/protocol/Xt2400Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xt2400Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/YwtProtocol.java b/src/main/java/org/traccar/protocol/YwtProtocol.java index fb44e2360..27c71cfa8 100644 --- a/src/main/java/org/traccar/protocol/YwtProtocol.java +++ b/src/main/java/org/traccar/protocol/YwtProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class YwtProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/reports/CombinedReportProvider.java b/src/main/java/org/traccar/reports/CombinedReportProvider.java index 63d6a9830..bad3a61b3 100644 --- a/src/main/java/org/traccar/reports/CombinedReportProvider.java +++ b/src/main/java/org/traccar/reports/CombinedReportProvider.java @@ -28,7 +28,7 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.util.ArrayList; import java.util.Collection; import java.util.Date; diff --git a/src/main/java/org/traccar/reports/CsvExportProvider.java b/src/main/java/org/traccar/reports/CsvExportProvider.java index df55c470e..521dc120a 100644 --- a/src/main/java/org/traccar/reports/CsvExportProvider.java +++ b/src/main/java/org/traccar/reports/CsvExportProvider.java @@ -21,7 +21,7 @@ import org.traccar.model.Position; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Date; diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java index ff7bc8e2f..f252f28cc 100644 --- a/src/main/java/org/traccar/reports/EventsReportProvider.java +++ b/src/main/java/org/traccar/reports/EventsReportProvider.java @@ -35,7 +35,7 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/reports/GpxExportProvider.java b/src/main/java/org/traccar/reports/GpxExportProvider.java index ccbd97fc3..1c45b6416 100644 --- a/src/main/java/org/traccar/reports/GpxExportProvider.java +++ b/src/main/java/org/traccar/reports/GpxExportProvider.java @@ -24,7 +24,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Date; diff --git a/src/main/java/org/traccar/reports/KmlExportProvider.java b/src/main/java/org/traccar/reports/KmlExportProvider.java index 24fcfb8ab..24dca018c 100644 --- a/src/main/java/org/traccar/reports/KmlExportProvider.java +++ b/src/main/java/org/traccar/reports/KmlExportProvider.java @@ -23,7 +23,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.OutputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index 5343652b7..d761fe1e5 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -32,7 +32,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index 57c57079d..2160fec0e 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -31,7 +31,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index 2226263fa..ffde0b067 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -35,7 +35,7 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index e6c3e7ffd..9ff7232af 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -31,7 +31,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/reports/common/ReportMailer.java b/src/main/java/org/traccar/reports/common/ReportMailer.java index 3ce41934f..9fb30fe9f 100644 --- a/src/main/java/org/traccar/reports/common/ReportMailer.java +++ b/src/main/java/org/traccar/reports/common/ReportMailer.java @@ -22,11 +22,11 @@ import org.traccar.mail.MailManager; import org.traccar.model.User; import org.traccar.storage.StorageException; -import javax.activation.DataHandler; -import javax.inject.Inject; -import javax.mail.MessagingException; -import javax.mail.internet.MimeBodyPart; -import javax.mail.util.ByteArrayDataSource; +import jakarta.activation.DataHandler; +import jakarta.inject.Inject; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeBodyPart; +import jakarta.mail.util.ByteArrayDataSource; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 995e92676..43db82708 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -52,8 +52,8 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.annotation.Nullable; -import javax.inject.Inject; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; diff --git a/src/main/java/org/traccar/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java index e1de3b3af..07cdb1fe1 100644 --- a/src/main/java/org/traccar/schedule/ScheduleManager.java +++ b/src/main/java/org/traccar/schedule/ScheduleManager.java @@ -18,8 +18,8 @@ package org.traccar.schedule; import com.google.inject.Injector; import org.traccar.LifecycleObject; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; diff --git a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java index 81567ec31..8e45568d5 100644 --- a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java +++ b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java @@ -27,7 +27,7 @@ import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; diff --git a/src/main/java/org/traccar/schedule/TaskHealthCheck.java b/src/main/java/org/traccar/schedule/TaskHealthCheck.java index a8c9873ce..abdc5af48 100644 --- a/src/main/java/org/traccar/schedule/TaskHealthCheck.java +++ b/src/main/java/org/traccar/schedule/TaskHealthCheck.java @@ -22,8 +22,8 @@ import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; -import javax.ws.rs.client.Client; +import jakarta.inject.Inject; +import jakarta.ws.rs.client.Client; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index 176b6d537..30f20f437 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.java @@ -39,7 +39,7 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.util.Collections; import java.util.Date; import java.util.List; diff --git a/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java b/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java index e6c2e8b6d..d9e0c6f0b 100644 --- a/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java +++ b/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java @@ -17,7 +17,7 @@ package org.traccar.schedule; import org.traccar.session.ConnectionManager; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index e6f5d00cf..28214840d 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -39,8 +39,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Arrays; diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 24abd7347..58320cf29 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -40,8 +40,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Arrays; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/org/traccar/sms/HttpSmsClient.java b/src/main/java/org/traccar/sms/HttpSmsClient.java index b4271a6f2..a2a0dd57f 100644 --- a/src/main/java/org/traccar/sms/HttpSmsClient.java +++ b/src/main/java/org/traccar/sms/HttpSmsClient.java @@ -21,11 +21,11 @@ import org.traccar.config.Keys; import org.traccar.helper.DataConverter; import org.traccar.notification.MessageException; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.Invocation; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java b/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java index edf089f37..60ad65f9e 100644 --- a/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java +++ b/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java @@ -17,11 +17,11 @@ package org.traccar.speedlimit; import org.traccar.helper.UnitsConverter; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.ws.rs.client.AsyncInvoker; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.InvocationCallback; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.AsyncInvoker; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.InvocationCallback; public class OverpassSpeedLimitProvider implements SpeedLimitProvider { diff --git a/src/main/java/org/traccar/storage/DatabaseModule.java b/src/main/java/org/traccar/storage/DatabaseModule.java index 3e3483818..9d9e5bd5e 100644 --- a/src/main/java/org/traccar/storage/DatabaseModule.java +++ b/src/main/java/org/traccar/storage/DatabaseModule.java @@ -29,7 +29,7 @@ import liquibase.resource.ResourceAccessor; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Singleton; +import jakarta.inject.Singleton; import javax.sql.DataSource; import java.io.File; import java.io.IOException; diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java index a049a641c..d20429319 100644 --- a/src/main/java/org/traccar/storage/DatabaseStorage.java +++ b/src/main/java/org/traccar/storage/DatabaseStorage.java @@ -27,7 +27,7 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.inject.Inject; +import jakarta.inject.Inject; import javax.sql.DataSource; import java.sql.SQLException; import java.util.HashMap; diff --git a/src/main/java/org/traccar/web/ConsoleServlet.java b/src/main/java/org/traccar/web/ConsoleServlet.java index 902a4f7a9..0012ba077 100644 --- a/src/main/java/org/traccar/web/ConsoleServlet.java +++ b/src/main/java/org/traccar/web/ConsoleServlet.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -16,7 +16,7 @@ package org.traccar.web; import org.h2.server.web.ConnectionInfo; -import org.h2.server.web.WebServlet; +import org.h2.server.web.JakartaWebServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; @@ -26,7 +26,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -public class ConsoleServlet extends WebServlet { +public class ConsoleServlet extends JakartaWebServlet { private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleServlet.class); @@ -41,7 +41,7 @@ public class ConsoleServlet extends WebServlet { super.init(); try { - Field field = WebServlet.class.getDeclaredField("server"); + Field field = JakartaWebServlet.class.getDeclaredField("server"); field.setAccessible(true); org.h2.server.web.WebServer server = (org.h2.server.web.WebServer) field.get(this); diff --git a/src/main/java/org/traccar/web/ModernDefaultServlet.java b/src/main/java/org/traccar/web/ModernDefaultServlet.java index 7911c0e7f..a7c8cdb29 100644 --- a/src/main/java/org/traccar/web/ModernDefaultServlet.java +++ b/src/main/java/org/traccar/web/ModernDefaultServlet.java @@ -20,7 +20,7 @@ import org.eclipse.jetty.util.resource.Resource; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.io.File; import java.io.IOException; diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java index 6d20789f2..f870c4147 100644 --- a/src/main/java/org/traccar/web/OverrideFilter.java +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -20,15 +20,15 @@ import org.traccar.api.security.PermissionsService; import org.traccar.model.Server; import org.traccar.storage.StorageException; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @Singleton diff --git a/src/main/java/org/traccar/web/ResponseWrapper.java b/src/main/java/org/traccar/web/ResponseWrapper.java index c6179a33e..a0eaf6788 100644 --- a/src/main/java/org/traccar/web/ResponseWrapper.java +++ b/src/main/java/org/traccar/web/ResponseWrapper.java @@ -15,10 +15,10 @@ */ package org.traccar.web; -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/main/java/org/traccar/web/ThrottlingFilter.java b/src/main/java/org/traccar/web/ThrottlingFilter.java index 6d2328562..1bad33db6 100644 --- a/src/main/java/org/traccar/web/ThrottlingFilter.java +++ b/src/main/java/org/traccar/web/ThrottlingFilter.java @@ -19,13 +19,13 @@ import org.eclipse.jetty.servlets.DoSFilter; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; @Singleton public class ThrottlingFilter extends DoSFilter { diff --git a/src/main/java/org/traccar/web/WebInjectionManagerFactory.java b/src/main/java/org/traccar/web/WebInjectionManagerFactory.java index 14d9d3dbc..3e73c41ad 100644 --- a/src/main/java/org/traccar/web/WebInjectionManagerFactory.java +++ b/src/main/java/org/traccar/web/WebInjectionManagerFactory.java @@ -23,7 +23,7 @@ import org.jvnet.hk2.guice.bridge.api.GuiceBridge; import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge; import org.traccar.Main; -import javax.annotation.Priority; +import jakarta.annotation.Priority; @Priority(20) public class WebInjectionManagerFactory implements InjectionManagerFactory { diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index 184c546d5..5f27f7662 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -52,11 +52,11 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.ObjectMapperContextResolver; -import javax.servlet.DispatcherType; -import javax.servlet.ServletException; -import javax.servlet.SessionCookieConfig; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.ServletException; +import jakarta.servlet.SessionCookieConfig; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import javax.sql.DataSource; import java.io.File; import java.io.IOException; diff --git a/src/test/java/org/traccar/geocoder/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java index 7ee0e68d0..1e1a98c1e 100644 --- a/src/test/java/org/traccar/geocoder/GeocoderTest.java +++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java @@ -3,8 +3,8 @@ package org.traccar.geocoder; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; import java.util.Locale; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java index 3e0729dff..da5ae3340 100644 --- a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java +++ b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java @@ -6,8 +6,8 @@ import org.traccar.BaseTest; import org.traccar.model.CellTower; import org.traccar.model.Network; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; diff --git a/src/test/java/org/traccar/helper/WebHelperTest.java b/src/test/java/org/traccar/helper/WebHelperTest.java index 3a7329cb8..da18be11e 100644 --- a/src/test/java/org/traccar/helper/WebHelperTest.java +++ b/src/test/java/org/traccar/helper/WebHelperTest.java @@ -2,7 +2,7 @@ package org.traccar.helper; import org.junit.jupiter.api.Test; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; diff --git a/src/test/java/org/traccar/notification/NotificiationMailTest.java b/src/test/java/org/traccar/notification/NotificiationMailTest.java index 41124140c..ccc8cc47d 100644 --- a/src/test/java/org/traccar/notification/NotificiationMailTest.java +++ b/src/test/java/org/traccar/notification/NotificiationMailTest.java @@ -3,11 +3,11 @@ package org.traccar.notification; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import javax.mail.Message; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; +import jakarta.mail.Message; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; import java.util.Properties; public class NotificiationMailTest { diff --git a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java index 5ea13bf9c..a59d1ce91 100644 --- a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java +++ b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java @@ -3,8 +3,8 @@ package org.traccar.speedlimit; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; -- cgit v1.2.3 From 860b8ba8b370f710dd5530253d8748bf6185f1fa Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 22 Aug 2023 00:27:36 +0400 Subject: Add periodic position fetching command for Gator protocol --- src/main/java/org/traccar/model/Command.java | 7 +++++-- .../java/org/traccar/protocol/GatorProtocol.java | 1 + .../org/traccar/protocol/GatorProtocolDecoder.java | 1 + .../org/traccar/protocol/GatorProtocolEncoder.java | 23 +++++++++++++++++----- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index 99988dd82..5b81fcfef 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -15,9 +15,8 @@ */ package org.traccar.model; -import org.traccar.storage.QueryIgnore; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.traccar.storage.QueryIgnore; import org.traccar.storage.StorageName; @StorageName("tc_commands") @@ -72,6 +71,10 @@ public class Command extends BaseCommand { public static final String KEY_UNIQUE_ID = "uniqueId"; public static final String KEY_FREQUENCY = "frequency"; + + public static final String KEY_ENGINE_OFF_INTERVAL = "engine_off_interval"; + public static final String KEY_ENGINE_ON_INTERVAL = "engine_on_interval"; + public static final String KEY_HEARTBEAT_INTERVAL = "heartbeat_interval"; public static final String KEY_LANGUAGE = "language"; public static final String KEY_TIMEZONE = "timezone"; public static final String KEY_DEVICE_PASSWORD = "devicePassword"; diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index 096095463..bdea0fb00 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -31,6 +31,7 @@ public class GatorProtocol extends BaseProtocol { setSupportedDataCommands(Command.TYPE_POSITION_SINGLE); setSupportedDataCommands(Command.TYPE_ENGINE_RESUME); setSupportedDataCommands(Command.TYPE_ENGINE_STOP); + setSupportedDataCommands(Command.TYPE_POSITION_PERIODIC); 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 a5ecb2169..bcd1a64b7 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -38,6 +38,7 @@ 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_POSITION_PERIODIC = 0x30; public static final int MSG_RESTORES_THE_OIL_DUCT = 0x38; public static final int MSG_CLOSE_THE_OIL_DUCT = 0x39; public static final int MSG_POSITION_DATA = 0x80; diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 6d96c6e9a..5452d83c7 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -43,18 +43,24 @@ 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 + + // ip 4 bytes, content length, checksum and end byte + buf.writeByte(4 + 1 + (content != null ? content.readableBytes() : 0) + 1); ByteBuf pseudoIPAddress = encodeId(deviceId); buf.writeBytes(pseudoIPAddress); + if (content != null) { + buf.writeBytes(content); + } + int checksum = Checksum.xor(buf.nioBuffer()); buf.writeByte(checksum); @@ -66,13 +72,20 @@ 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, content); case Command.TYPE_ENGINE_STOP: - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_THE_OIL_DUCT); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_THE_OIL_DUCT, content); case Command.TYPE_ENGINE_RESUME: - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESTORES_THE_OIL_DUCT); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESTORES_THE_OIL_DUCT, content); + case Command.TYPE_POSITION_PERIODIC: + content.writeShort(command.getInteger(Command.KEY_ENGINE_ON_INTERVAL)); + content.writeShort(command.getInteger(Command.KEY_ENGINE_OFF_INTERVAL)); + content.writeByte(command.getInteger(Command.KEY_HEARTBEAT_INTERVAL)); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_PERIODIC, content); default: return null; } -- cgit v1.2.3 From 09d4fb4a10a5362191023f5c82327d8d38ae830f Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 22 Aug 2023 01:29:10 +0400 Subject: Fix position periodic command code --- src/main/java/org/traccar/protocol/GatorProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index bcd1a64b7..c68546c00 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -38,7 +38,7 @@ 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_POSITION_PERIODIC = 0x30; + public static final int MSG_POSITION_PERIODIC = 0x34; public static final int MSG_RESTORES_THE_OIL_DUCT = 0x38; public static final int MSG_CLOSE_THE_OIL_DUCT = 0x39; public static final int MSG_POSITION_DATA = 0x80; -- cgit v1.2.3 From 75064707c6432cc4918eab573ac3ce9d6eee1d94 Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 22 Aug 2023 02:11:40 +0400 Subject: Add command to set speed limit and odometer for Gator - Add test to verify position retrieval interval settings - Update key name MSG_POSITION_PERIODIC to MSG_SET_POSITION_REQUEST_INTERVAL --- src/main/java/org/traccar/protocol/GatorProtocol.java | 2 ++ .../java/org/traccar/protocol/GatorProtocolDecoder.java | 4 +++- .../java/org/traccar/protocol/GatorProtocolEncoder.java | 8 +++++++- .../org/traccar/protocol/GatorProtocolEncoderTest.java | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index bdea0fb00..0f44fbf47 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -32,6 +32,8 @@ public class GatorProtocol extends BaseProtocol { setSupportedDataCommands(Command.TYPE_ENGINE_RESUME); setSupportedDataCommands(Command.TYPE_ENGINE_STOP); setSupportedDataCommands(Command.TYPE_POSITION_PERIODIC); + setSupportedDataCommands(Command.TYPE_SET_SPEED_LIMIT); + setSupportedDataCommands(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 c68546c00..90fd5d0c6 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -38,7 +38,9 @@ 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_POSITION_PERIODIC = 0x34; + public static final int MSG_SET_POSITION_REQUEST_INTERVAL = 0x34; + public static final int MSG_SET_SPEED_LIMIT = 0x3F; + public static final int MSG_SET_ODOMETER = 0x6B; public static final int MSG_RESTORES_THE_OIL_DUCT = 0x38; public static final int MSG_CLOSE_THE_OIL_DUCT = 0x39; public static final int MSG_POSITION_DATA = 0x80; diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 5452d83c7..570dd269a 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -81,11 +81,17 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_THE_OIL_DUCT, content); case Command.TYPE_ENGINE_RESUME: return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESTORES_THE_OIL_DUCT, content); + case Command.TYPE_SET_SPEED_LIMIT: + content.writeByte(command.getInteger(Command.KEY_DATA)); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_SET_SPEED_LIMIT, content); + case Command.TYPE_SET_ODOMETER: + content.writeShort(command.getInteger(Command.KEY_DATA)); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_SET_ODOMETER, content); case Command.TYPE_POSITION_PERIODIC: content.writeShort(command.getInteger(Command.KEY_ENGINE_ON_INTERVAL)); content.writeShort(command.getInteger(Command.KEY_ENGINE_OFF_INTERVAL)); content.writeByte(command.getInteger(Command.KEY_HEARTBEAT_INTERVAL)); - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_PERIODIC, content); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_SET_POSITION_REQUEST_INTERVAL, content); default: return null; } diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index af6c71e37..7938ab630 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -20,4 +20,19 @@ public class GatorProtocolEncoderTest extends ProtocolTest { command.setType(Command.TYPE_POSITION_SINGLE); verifyCommand(encoder, command, binary("24243000062008958C070D")); } + + @Test + public void testEncodePeriodicPositionRetrievalIntervalSet() throws Exception { + var encoder = inject(new GatorProtocolEncoder(null)); + var device = encoder.getCacheManager().getObject(Device.class, 1); + when(device.getUniqueId()).thenReturn("13088005658"); + + Command command = new Command(); + command.setDeviceId(1); + command.set("heartbeat_interval", 120); + command.set("engine_off_interval", 5); + command.set("engine_on_interval", 5); + command.setType(Command.TYPE_POSITION_PERIODIC); + verifyCommand(encoder, command, binary("242434000b5800383a00050005781d0d")); + } } -- cgit v1.2.3 From 0b1b54428a6f3cc66dd1aed57de05545e4e7d30a Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 22 Aug 2023 02:30:27 +0400 Subject: Reset MSG_SET_POSITION_REQUEST_INTERVAL to MSG_POSITION_PERIODIC - As the Line is longer than 120 characters, changed the variable name to fix the issue --- src/main/java/org/traccar/protocol/GatorProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index 90fd5d0c6..0202ed7d0 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -38,7 +38,7 @@ 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_SET_POSITION_REQUEST_INTERVAL = 0x34; + public static final int MSG_POSITION_PERIODIC = 0x34; public static final int MSG_SET_SPEED_LIMIT = 0x3F; public static final int MSG_SET_ODOMETER = 0x6B; public static final int MSG_RESTORES_THE_OIL_DUCT = 0x38; diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 570dd269a..d613b30c2 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -91,7 +91,7 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { content.writeShort(command.getInteger(Command.KEY_ENGINE_ON_INTERVAL)); content.writeShort(command.getInteger(Command.KEY_ENGINE_OFF_INTERVAL)); content.writeByte(command.getInteger(Command.KEY_HEARTBEAT_INTERVAL)); - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_SET_POSITION_REQUEST_INTERVAL, content); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_PERIODIC, content); default: return null; } -- cgit v1.2.3 From cadcd2676adbc1974265acb9ec6d43fc06932824 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 21 Aug 2023 21:09:46 -0700 Subject: Atelematics battery level --- src/main/java/org/traccar/protocol/KhdProtocolDecoder.java | 3 +++ src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java index d7c236c4f..dd2e1dbfd 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java @@ -205,6 +205,9 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { } } break; + case 0x20: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + break; case 0x23: Network network = new Network(); int count = buf.readUnsignedByte(); diff --git a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java index b7e868077..7cc65002b 100644 --- a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class KhdProtocolDecoderTest extends ProtocolTest { @@ -10,6 +11,10 @@ public class KhdProtocolDecoderTest extends ProtocolTest { var decoder = inject(new KhdProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "2929a3003e1680ba0a2304180759500000000000000000000000007b00000080001914000000000000000000162001641b0b0000249002bc58030001cc46020000e70d"), + Position.KEY_BATTERY_LEVEL, 100); + verifyPosition(decoder, binary( "2929800028258b8c10210731035840031534240542120200000337fb000000ffff5a00000a0000000005005d0d")); -- cgit v1.2.3 From ee6b094d26ef8015299cd4a239a415be0cab57f0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 22 Aug 2023 06:47:29 -0700 Subject: Configurable TAIP speed unit --- src/main/java/org/traccar/protocol/TaipProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java index e5e84b7c4..cf72eef42 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -192,7 +192,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); } - position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); + position.setSpeed(convertSpeed(parser.nextDouble(0), "mph")); position.setCourse(parser.nextDouble(0)); if (parser.hasNext(2)) { -- cgit v1.2.3 From 50e730c0cbbe253b68a2db0e57920ddc3a1b3814 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 22 Aug 2023 06:50:52 -0700 Subject: Remove unused import --- src/main/java/org/traccar/protocol/TaipProtocolDecoder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java index cf72eef42..787ed1599 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -26,7 +26,6 @@ import org.traccar.helper.DateBuilder; import org.traccar.helper.DateUtil; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; import java.net.SocketAddress; -- cgit v1.2.3 From 9aeedc90da24848ff97227d6f281eb4d1e1506ef Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 23 Aug 2023 21:01:38 -0700 Subject: Add speed limit multiplier (fix #5161) --- src/main/java/org/traccar/config/Keys.java | 9 +++++++++ .../java/org/traccar/handler/events/OverspeedEventHandler.java | 6 ++++-- .../java/org/traccar/session/state/OverspeedProcessor.java | 7 ++++--- .../org/traccar/handler/events/OverspeedEventHandlerTest.java | 10 +++++----- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index f95794e03..27f5f0921 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -340,6 +340,15 @@ public final class Keys { List.of(KeyType.SERVER, KeyType.DEVICE), 0.0); + /** + * Speed limit threshold multiplier. For example, if the speed limit is 100, but we only want to generate an event + * if the speed is higher than 105, this parameter can be set to 1.05. Default multiplier is 1.0. + */ + public static final ConfigKey EVENT_OVERSPEED_THRESHOLD_MULTIPLIER = new DoubleConfigKey( + "event.overspeed.thresholdMultiplier", + List.of(KeyType.CONFIG), + 1.0); + /** * Minimal over speed duration to trigger the event. Value in seconds. */ diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 94fdc4699..3bb5f713c 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,6 +52,7 @@ public class OverspeedEventHandler extends BaseEventHandler { private final long minimalDuration; private final boolean preferLowest; + private final double multiplier; @Inject public OverspeedEventHandler( @@ -60,6 +61,7 @@ public class OverspeedEventHandler extends BaseEventHandler { this.storage = storage; minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000; preferLowest = config.getBoolean(Keys.EVENT_OVERSPEED_PREFER_LOWEST); + multiplier = config.getDouble(Keys.EVENT_OVERSPEED_THRESHOLD_MULTIPLIER); } @Override @@ -107,7 +109,7 @@ public class OverspeedEventHandler extends BaseEventHandler { } OverspeedState state = OverspeedState.fromDevice(device); - OverspeedProcessor.updateState(state, position, speedLimit, minimalDuration, overspeedGeofenceId); + OverspeedProcessor.updateState(state, position, speedLimit, multiplier, minimalDuration, overspeedGeofenceId); if (state.isChanged()) { state.toDevice(device); try { diff --git a/src/main/java/org/traccar/session/state/OverspeedProcessor.java b/src/main/java/org/traccar/session/state/OverspeedProcessor.java index b23649570..221b51ff5 100644 --- a/src/main/java/org/traccar/session/state/OverspeedProcessor.java +++ b/src/main/java/org/traccar/session/state/OverspeedProcessor.java @@ -26,13 +26,14 @@ public final class OverspeedProcessor { } public static void updateState( - OverspeedState state, Position position, double speedLimit, long minimalDuration, long geofenceId) { + OverspeedState state, Position position, + double speedLimit, double multiplier, long minimalDuration, long geofenceId) { state.setEvent(null); boolean oldState = state.getOverspeedState(); if (oldState) { - boolean newState = position.getSpeed() > speedLimit; + boolean newState = position.getSpeed() > speedLimit * multiplier; if (newState) { checkEvent(state, position, speedLimit, minimalDuration); } else { @@ -40,7 +41,7 @@ public final class OverspeedProcessor { state.setOverspeedTime(null); state.setOverspeedGeofenceId(0); } - } else if (position != null && position.getSpeed() > speedLimit) { + } else if (position != null && position.getSpeed() > speedLimit * multiplier) { state.setOverspeedState(true); state.setOverspeedTime(position.getFixTime()); state.setOverspeedGeofenceId(geofenceId); diff --git a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java index 25e9bd265..97d929551 100644 --- a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java @@ -35,14 +35,14 @@ public class OverspeedEventHandlerTest extends BaseTest { private void testOverspeedWithPosition(long geofenceId) throws ParseException { OverspeedState state = new OverspeedState(); - OverspeedProcessor.updateState(state, position("2017-01-01 00:00:00", 50), 40, 15000, geofenceId); + OverspeedProcessor.updateState(state, position("2017-01-01 00:00:00", 50), 40, 1, 15000, geofenceId); assertNull(state.getEvent()); verifyState(state, true, geofenceId); - OverspeedProcessor.updateState(state, position("2017-01-01 00:00:10", 55), 40, 15000, geofenceId); + OverspeedProcessor.updateState(state, position("2017-01-01 00:00:10", 55), 40, 1, 15000, geofenceId); assertNull(state.getEvent()); - OverspeedProcessor.updateState(state, position("2017-01-01 00:00:20", 55), 40, 15000, geofenceId); + OverspeedProcessor.updateState(state, position("2017-01-01 00:00:20", 55), 40, 1, 15000, geofenceId); assertNotNull(state.getEvent()); assertEquals(Event.TYPE_DEVICE_OVERSPEED, state.getEvent().getType()); assertEquals(55, state.getEvent().getDouble("speed"), 0.1); @@ -50,11 +50,11 @@ public class OverspeedEventHandlerTest extends BaseTest { assertEquals(geofenceId, state.getEvent().getGeofenceId()); verifyState(state, true, 0); - OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 55), 40, 15000, geofenceId); + OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 55), 40, 1, 15000, geofenceId); assertNull(state.getEvent()); verifyState(state, true, 0); - OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 30), 40, 15000, geofenceId); + OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 30), 40, 1, 15000, geofenceId); assertNull(state.getEvent()); verifyState(state, false, 0); } -- cgit v1.2.3 From fd92fa10d8bcbe8bca5a9212e3410d17ed9d280f Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Thu, 24 Aug 2023 22:58:36 +0300 Subject: - update fork; - refactor param checks, delete nulls; - add field 4 (alarm, armed); - add field 5 (roaming); - fix hours params; - fix accelerator and brake position keys; - move fields 78-83 (fuel temperature); - add fields 163-166 (high precision temperature); - add fields 167-170 (humidity); - add field 206 (diagnostics param); - add fields 207-255 (user parameters). --- .../protocol/NavtelecomProtocolDecoder.java | 193 ++++++++++++++++----- 1 file changed, 148 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 87cccbeaa..6ef614c8d 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -208,6 +208,19 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 3: position.setDeviceTime(new Date(buf.readUnsignedIntLE() * 1000)); break; + case 4: + value = buf.readUnsignedByte(); + position.set(Position.KEY_ALARM, BitUtil.check(value, 2)); + int guardMode = BitUtil.between(value, 3, 4); + position.set( + Position.KEY_ARMED, + (0 < guardMode) && (guardMode < 3)); + break; + + case 5: + value = buf.readUnsignedByte(); + position.set(Position.KEY_ROAMING, BitUtil.check(value, 6)); + break; case 8: value = buf.readUnsignedByte(); position.setValid(BitUtil.check(value, 1)); @@ -269,7 +282,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { position.set("freq" + (j + 2 - 35), buf.readUnsignedShortLE()); break; case 37: - position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() / 60); + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); break; case 38: case 39: @@ -278,11 +291,15 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 42: case 43: value = buf.readUnsignedShortLE(); - position.set("fuel" + (j + 2 - 38), (value < 65500) ? value : null); + if (value < 65500) { + position.set("fuel" + (j + 2 - 38), value); + } break; case 44: value = buf.readUnsignedShortLE(); - position.set(Position.KEY_FUEL_LEVEL, (value < 65500) ? value : null); + if (value < 65500) { + position.set(Position.KEY_FUEL_LEVEL, value); + } break; case 45: case 46: @@ -293,29 +310,18 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 51: case 52: value = buf.readByte(); - position.set( - Position.PREFIX_TEMP + (j + 2 - 45), - (value != (byte) 0x80) ? value : null); - break; - case 78: - case 79: - case 80: - case 81: - case 82: - case 83: - position.set("fuelTemp" + (j + 2 - 78), (int) buf.readByte()); + if (value != (byte) 0x80) { + position.set(Position.PREFIX_TEMP + (j + 2 - 45), value); + } break; case 53: value = buf.readUnsignedShortLE(); - if (value == 0x7FFF) { - position.set("fuelLevel", (Boolean) null); - position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); - } else if (BitUtil.check(value, 7)) { - position.set("fuelLevel", BitUtil.to(value, 6)); - position.set(Position.KEY_FUEL_LEVEL, (Boolean) null); - } else { - position.set("fuelLevel", (Boolean) null); - position.set(Position.KEY_FUEL_LEVEL, BitUtil.to(value, 6) / 10); + if (value != 0x7FFF) { + if (BitUtil.check(value, 7)) { + position.set("fuelLevel", BitUtil.to(value, 6)); + } else { + position.set(Position.KEY_FUEL_LEVEL, BitUtil.to(value, 6) / 10); + } } break; case 54: @@ -323,11 +329,15 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 55: value = buf.readUnsignedShortLE(); - position.set(Position.KEY_RPM, (value != 0xFFFF) ? value : null); + if (value != 0xFFFF) { + position.set(Position.KEY_RPM, value); + } break; case 56: value = buf.readByte(); - position.set(Position.KEY_COOLANT_TEMP, (value != 0x80) ? value : null); + if (value != (byte) 0x80) { + position.set(Position.KEY_COOLANT_TEMP, value); + } break; case 57: position.set(Position.KEY_OBD_ODOMETER, buf.readFloatLE()); @@ -338,47 +348,140 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 61: case 62: value = buf.readUnsignedShortLE(); - position.set( - Position.KEY_AXLE_WEIGHT + (j + 2 - 58), (value != 65535) ? value : null); + if (value != 0xFFFF) { + position.set(Position.KEY_AXLE_WEIGHT + (j + 2 - 58), value); + } break; case 63: value = buf.readUnsignedByte(); - position.set("obdAccelPos", (value != 0xFF) ? value : null); + if (value != 0xFF) { + position.set("acceleratorPosition", value); + } break; case 64: value = buf.readUnsignedByte(); - position.set("obdBrakePos", (value != 0xFF) ? value : null); + if (value != 0xFF) { + position.set("brakePosition", value); + } break; case 65: value = buf.readUnsignedByte(); - position.set(Position.KEY_ENGINE_LOAD, (value != 0xFF) ? value : null); + if (value != 0xFF) { + position.set(Position.KEY_ENGINE_LOAD, value); + } break; case 66: value = buf.readUnsignedShortLE(); - if (value == 0x7FFF) { - position.set("obdAdBlueLevel", (Boolean) null); - position.set("obdAdBlue", (Boolean) null); - } else if (BitUtil.check(value, 7)) { - position.set("obdAdBlueLevel", BitUtil.to(value, 6)); - position.set("obdAdBlue", (Boolean) null); - } else { - position.set("obdAdBlueLevel", (Boolean) null); - position.set("obdAdBlue", BitUtil.to(value, 6) / 10); + if (value != 0x7FFF) { + if (BitUtil.check(value, 7)) { + position.set("obdAdBlueLevel", BitUtil.to(value, 6)); + } else { + position.set("obdAdBlue", BitUtil.to(value, 6) / 10); + } } break; case 67: - position.set("obdHours", buf.readUnsignedIntLE() / 60); + position.set("obdHours", buf.readUnsignedIntLE() * 1000); break; case 68: value = buf.readUnsignedShortLE(); - position.set( - Position.KEY_ODOMETER_SERVICE, (value != 0xFFFF) ? (value * 5000) : null); + if (value != 0xFFFF) { + position.set(Position.KEY_ODOMETER_SERVICE, (value * 5000)); + } break; case 69: value = buf.readUnsignedByte(); - position.set( - Position.KEY_OBD_SPEED, - (value != 0xFF) ? UnitsConverter.knotsFromKph(value) : null); + if (value != 0xFF) { + position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(value)); + } + break; + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + position.set("fuelTemp" + (j + 2 - 78), (int) buf.readByte()); + break; + case 163: + case 164: + case 165: + case 166: + value = buf.readShortLE(); + if (value != (short) 0x8000) { + position.set( + Position.PREFIX_TEMP + "HighPrecision" + (j + 2 - 163), + value * 0.05); + } + break; + case 167: + case 168: + case 169: + case 170: + value = buf.readUnsignedByte(); + if (value != 0xFF) { + position.set("humidity" + (j + 2 - 167), value * 0.5); + } + break; + case 206: + position.set("diagnostic", buf.readUnsignedIntLE()); + break; + case 207: + case 208: + case 209: + case 210: + case 211: + case 212: + case 213: + case 214: + case 215: + case 216: + case 217: + case 218: + case 219: + case 220: + case 221: + case 222: + position.set("user1Byte" + (j + 2 - 207), buf.readUnsignedByte()); + break; + case 223: + case 224: + case 225: + case 226: + case 227: + case 228: + case 229: + case 230: + case 231: + case 232: + case 233: + case 234: + case 235: + case 236: + case 237: + position.set("user2Byte" + (j + 2 - 223), buf.readUnsignedShortLE()); + break; + case 238: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: + case 246: + case 247: + case 248: + case 249: + case 250: + case 251: + case 252: + position.set("user4Byte" + (j + 2 - 238), buf.readUnsignedIntLE()); + break; + case 253: + case 254: + case 255: + position.set("user8Byte" + (j + 2 - 253), buf.readLongLE()); break; default: buf.skipBytes(getItemLength(j + 1)); -- cgit v1.2.3 From 500d563d1923503b9e835c3f4a4a894bba883bf7 Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Fri, 25 Aug 2023 15:44:48 +0300 Subject: correction of comments: - rollback, returned the condition operator; - everything that fits in one line now; - fixed the key for fields 163-166; - parsing of fields 207-255 has been moved to default. --- .../protocol/NavtelecomProtocolDecoder.java | 141 ++++++--------------- 1 file changed, 38 insertions(+), 103 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 6ef614c8d..f317bee13 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -212,9 +212,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { value = buf.readUnsignedByte(); position.set(Position.KEY_ALARM, BitUtil.check(value, 2)); int guardMode = BitUtil.between(value, 3, 4); - position.set( - Position.KEY_ARMED, - (0 < guardMode) && (guardMode < 3)); + position.set(Position.KEY_ARMED, (0 < guardMode) && (guardMode < 3)); break; case 5: @@ -291,15 +289,11 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 42: case 43: value = buf.readUnsignedShortLE(); - if (value < 65500) { - position.set("fuel" + (j + 2 - 38), value); - } + position.set("fuel" + (j + 2 - 38), (value < 65500) ? value : null); break; case 44: value = buf.readUnsignedShortLE(); - if (value < 65500) { - position.set(Position.KEY_FUEL_LEVEL, value); - } + position.set(Position.KEY_FUEL_LEVEL, (value < 65500) ? value : null); break; case 45: case 46: @@ -310,9 +304,8 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 51: case 52: value = buf.readByte(); - if (value != (byte) 0x80) { - position.set(Position.PREFIX_TEMP + (j + 2 - 45), value); - } + position.set( + Position.PREFIX_TEMP + (j + 2 - 45), (value != (byte) 0x80) ? value : null); break; case 53: value = buf.readUnsignedShortLE(); @@ -329,15 +322,11 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 55: value = buf.readUnsignedShortLE(); - if (value != 0xFFFF) { - position.set(Position.KEY_RPM, value); - } + position.set(Position.KEY_RPM, (value != 0xFFFF) ? value : null); break; case 56: value = buf.readByte(); - if (value != (byte) 0x80) { - position.set(Position.KEY_COOLANT_TEMP, value); - } + position.set(Position.KEY_COOLANT_TEMP, (value != (byte) 0x80) ? value : null); break; case 57: position.set(Position.KEY_OBD_ODOMETER, buf.readFloatLE()); @@ -348,27 +337,20 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 61: case 62: value = buf.readUnsignedShortLE(); - if (value != 0xFFFF) { - position.set(Position.KEY_AXLE_WEIGHT + (j + 2 - 58), value); - } + position.set( + Position.KEY_AXLE_WEIGHT + (j + 2 - 58), (value != 0xFFFF) ? value : null); break; case 63: value = buf.readUnsignedByte(); - if (value != 0xFF) { - position.set("acceleratorPosition", value); - } + position.set("acceleratorPosition", (value != 0xFF) ? value : null); break; case 64: value = buf.readUnsignedByte(); - if (value != 0xFF) { - position.set("brakePosition", value); - } + position.set("brakePosition", (value != 0xFF) ? value : null); break; case 65: value = buf.readUnsignedByte(); - if (value != 0xFF) { - position.set(Position.KEY_ENGINE_LOAD, value); - } + position.set(Position.KEY_ENGINE_LOAD, (value != 0xFF) ? value : null); break; case 66: value = buf.readUnsignedShortLE(); @@ -385,15 +367,15 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 68: value = buf.readUnsignedShortLE(); - if (value != 0xFFFF) { - position.set(Position.KEY_ODOMETER_SERVICE, (value * 5000)); - } + position.set( + Position.KEY_ODOMETER_SERVICE, + (value != 0xFFFF) ? (value * 5000) : null); break; case 69: value = buf.readUnsignedByte(); - if (value != 0xFF) { - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(value)); - } + position.set( + Position.KEY_OBD_SPEED, + (value != 0xFF) ? UnitsConverter.knotsFromKph(value) : null); break; case 78: case 79: @@ -408,84 +390,37 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 165: case 166: value = buf.readShortLE(); - if (value != (short) 0x8000) { - position.set( - Position.PREFIX_TEMP + "HighPrecision" + (j + 2 - 163), - value * 0.05); - } + position.set( + Position.PREFIX_TEMP + (j + 2 + 8 - 163), + (value != (short) 0x8000) ? value * 0.05 : null); break; case 167: case 168: case 169: case 170: value = buf.readUnsignedByte(); - if (value != 0xFF) { - position.set("humidity" + (j + 2 - 167), value * 0.5); - } + position.set("humidity" + (j + 2 - 167), (value != 0xFF) ? value * 0.5 : null); break; case 206: position.set("diagnostic", buf.readUnsignedIntLE()); break; - case 207: - case 208: - case 209: - case 210: - case 211: - case 212: - case 213: - case 214: - case 215: - case 216: - case 217: - case 218: - case 219: - case 220: - case 221: - case 222: - position.set("user1Byte" + (j + 2 - 207), buf.readUnsignedByte()); - break; - case 223: - case 224: - case 225: - case 226: - case 227: - case 228: - case 229: - case 230: - case 231: - case 232: - case 233: - case 234: - case 235: - case 236: - case 237: - position.set("user2Byte" + (j + 2 - 223), buf.readUnsignedShortLE()); - break; - case 238: - case 239: - case 240: - case 241: - case 242: - case 243: - case 244: - case 245: - case 246: - case 247: - case 248: - case 249: - case 250: - case 251: - case 252: - position.set("user4Byte" + (j + 2 - 238), buf.readUnsignedIntLE()); - break; - case 253: - case 254: - case 255: - position.set("user8Byte" + (j + 2 - 253), buf.readLongLE()); - break; default: - buf.skipBytes(getItemLength(j + 1)); - break; + if ((207 <= j) && (j <= 222)) { + position.set("user1Byte" + (j + 2 - 207), buf.readUnsignedByte()); + break; + } else if ((223 <= j) && (j <= 237)) { + position.set("user2Byte" + (j + 2 - 223), buf.readUnsignedShortLE()); + break; + } else if ((238 <= j) && (j <= 252)) { + position.set("user4Byte" + (j + 2 - 238), buf.readUnsignedIntLE()); + break; + } else if ((253 <= j) && (j <= 255)) { + position.set("user8Byte" + (j + 2 - 253), buf.readLongLE()); + break; + } else { + buf.skipBytes(getItemLength(j + 1)); + break; + } } } } -- cgit v1.2.3 From 6ac4b94179ae340157c59d995d042ed238e9696d Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Sat, 26 Aug 2023 00:13:15 +0300 Subject: correction: - fix alarm; - fix roaming; - rename field 44 to fuel without index (this is initial sensor in device); - rename field 53 to obdFuel (this is from CAN bus); - fix axle weight name; - fix breaks in default block. --- .../traccar/protocol/NavtelecomProtocolDecoder.java | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index f317bee13..51b7db763 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -210,14 +210,16 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 4: value = buf.readUnsignedByte(); - position.set(Position.KEY_ALARM, BitUtil.check(value, 2)); + position.set( + Position.KEY_ALARM, + BitUtil.check(value, 2) ? Position.ALARM_GENERAL : null); int guardMode = BitUtil.between(value, 3, 4); position.set(Position.KEY_ARMED, (0 < guardMode) && (guardMode < 3)); break; case 5: value = buf.readUnsignedByte(); - position.set(Position.KEY_ROAMING, BitUtil.check(value, 6)); + position.set(Position.KEY_ROAMING, BitUtil.check(value, 6) ? true : null); break; case 8: value = buf.readUnsignedByte(); @@ -293,7 +295,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 44: value = buf.readUnsignedShortLE(); - position.set(Position.KEY_FUEL_LEVEL, (value < 65500) ? value : null); + position.set("fuel", (value < 65500) ? value : null); break; case 45: case 46: @@ -311,9 +313,9 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { value = buf.readUnsignedShortLE(); if (value != 0x7FFF) { if (BitUtil.check(value, 7)) { - position.set("fuelLevel", BitUtil.to(value, 6)); + position.set("obdFuelLevel", BitUtil.to(value, 6)); } else { - position.set(Position.KEY_FUEL_LEVEL, BitUtil.to(value, 6) / 10); + position.set("obdFuel", BitUtil.to(value, 6) / 10); } } break; @@ -337,8 +339,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 61: case 62: value = buf.readUnsignedShortLE(); - position.set( - Position.KEY_AXLE_WEIGHT + (j + 2 - 58), (value != 0xFFFF) ? value : null); + position.set("axleWeight" + (j + 2 - 58), (value != 0xFFFF) ? value : null); break; case 63: value = buf.readUnsignedByte(); @@ -407,20 +408,16 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { default: if ((207 <= j) && (j <= 222)) { position.set("user1Byte" + (j + 2 - 207), buf.readUnsignedByte()); - break; } else if ((223 <= j) && (j <= 237)) { position.set("user2Byte" + (j + 2 - 223), buf.readUnsignedShortLE()); - break; } else if ((238 <= j) && (j <= 252)) { position.set("user4Byte" + (j + 2 - 238), buf.readUnsignedIntLE()); - break; } else if ((253 <= j) && (j <= 255)) { position.set("user8Byte" + (j + 2 - 253), buf.readLongLE()); - break; } else { buf.skipBytes(getItemLength(j + 1)); - break; } + break; } } } -- cgit v1.2.3 From eb2021058ae754cf75ce2c303581de98e9f0f53f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 26 Aug 2023 07:41:30 -0700 Subject: Decode Starcom Helios attributes --- src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java index 56ab733c8..e758a8bb8 100644 --- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java @@ -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/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 @@ -10,6 +10,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")); -- cgit v1.2.3 From 4a5b8d79b560c7941960cc47c551d87b1a942320 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 26 Aug 2023 07:48:29 -0700 Subject: Fix odometer decoding --- src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java index e758a8bb8..36d66935c 100644 --- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java @@ -76,6 +76,7 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder { 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": -- cgit v1.2.3 From 28ccd407642bac5ded03a256c43349dff9a67ee4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 26 Aug 2023 15:04:20 -0700 Subject: Remove deleted account session --- src/main/java/org/traccar/api/resource/UserResource.java | 15 +++++++++++++++ .../org/traccar/api/security/SecurityRequestFilter.java | 9 ++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) 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 { @Inject private Config config; + @Context + private HttpServletRequest request; + public UserResource() { super(User.class); } @@ -111,4 +118,12 @@ public class UserResource extends BaseObjectResource { 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)); + } } } -- cgit v1.2.3 From 44236d51aa70c2e07356f4d430aee8ddc04e74dd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 26 Aug 2023 15:55:52 -0700 Subject: Update app icons --- src/main/java/org/traccar/web/OverrideFilter.java | 2 +- tools/test-generator.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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 -- cgit v1.2.3 From 570e97d2f6880711e13674f188e2d3666b239ce9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 27 Aug 2023 06:51:05 -0700 Subject: Separate Starcom mileage value --- src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java index 36d66935c..325847b16 100644 --- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java @@ -75,7 +75,6 @@ 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; -- cgit v1.2.3 From ffd116961741a81748f21d90d34fe63120928575 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 27 Aug 2023 08:10:39 -0700 Subject: Support GPS GF-22 WiFi info --- .../org/traccar/protocol/TrvProtocolDecoder.java | 43 +++++++++++++++++----- .../traccar/protocol/TrvProtocolDecoderTest.java | 5 ++- 2 files changed, 37 insertions(+), 11 deletions(-) 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/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 @@ -13,6 +13,9 @@ public class TrvProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, text( "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")); @@ -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#")); } -- cgit v1.2.3 From f7ad63b6f898a38d97fe2e200c688d04c2b051ff Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 27 Aug 2023 14:24:36 -0700 Subject: Extract base MQTT decoder --- .../java/org/traccar/BaseMqttProtocolDecoder.java | 96 ++++++++++++++ .../org/traccar/protocol/IotmProtocolDecoder.java | 147 +++++++-------------- 2 files changed, 141 insertions(+), 102 deletions(-) create mode 100644 src/main/java/org/traccar/BaseMqttProtocolDecoder.java 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/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 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 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; } } -- cgit v1.2.3 From 88bff45bd959ec932e00db9b3642e337abbcf1be Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 27 Aug 2023 14:56:45 -0700 Subject: Positioning Universal PUI Enterprise --- setup/default.xml | 1 + .../java/org/traccar/protocol/PuiProtocol.java | 40 ++++++++++++ .../org/traccar/protocol/PuiProtocolDecoder.java | 73 ++++++++++++++++++++++ .../traccar/protocol/PuiProtocolDecoderTest.java | 23 +++++++ 4 files changed, 137 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/PuiProtocol.java create mode 100644 src/main/java/org/traccar/protocol/PuiProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java 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 @@ 5246 5247 5248 + 5249 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/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()); + + } + +} -- cgit v1.2.3 From 0f38debb59b40ea9eeb89b93cdd4aeced2567f6d Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 29 Aug 2023 15:49:43 +0400 Subject: Use already existing keys to get params --- src/main/java/org/traccar/model/Command.java | 3 --- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 7 ++++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index 5b81fcfef..900436a01 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -72,9 +72,6 @@ public class Command extends BaseCommand { public static final String KEY_UNIQUE_ID = "uniqueId"; public static final String KEY_FREQUENCY = "frequency"; - public static final String KEY_ENGINE_OFF_INTERVAL = "engine_off_interval"; - public static final String KEY_ENGINE_ON_INTERVAL = "engine_on_interval"; - public static final String KEY_HEARTBEAT_INTERVAL = "heartbeat_interval"; public static final String KEY_LANGUAGE = "language"; public static final String KEY_TIMEZONE = "timezone"; public static final String KEY_DEVICE_PASSWORD = "devicePassword"; diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index d613b30c2..4a3e21d85 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -88,9 +88,10 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { content.writeShort(command.getInteger(Command.KEY_DATA)); return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_SET_ODOMETER, content); case Command.TYPE_POSITION_PERIODIC: - content.writeShort(command.getInteger(Command.KEY_ENGINE_ON_INTERVAL)); - content.writeShort(command.getInteger(Command.KEY_ENGINE_OFF_INTERVAL)); - content.writeByte(command.getInteger(Command.KEY_HEARTBEAT_INTERVAL)); + String[] data = command.getString(Command.KEY_FREQUENCY).split(";"); + content.writeShort(Integer.valueOf(data[0])); + content.writeShort(Integer.valueOf(data[1])); + content.writeShort(Integer.valueOf(data[2])); return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_PERIODIC, content); default: return null; -- cgit v1.2.3 From 2dd48fa51b39489aff03e4d0ede2e4be196283ec Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 29 Aug 2023 16:07:06 +0400 Subject: Fix test for encoding gator command --- src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index 7938ab630..1559e8294 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -29,9 +29,7 @@ public class GatorProtocolEncoderTest extends ProtocolTest { Command command = new Command(); command.setDeviceId(1); - command.set("heartbeat_interval", 120); - command.set("engine_off_interval", 5); - command.set("engine_on_interval", 5); + command.set(command.KEY_FREQUENCY, "5;5;120"); command.setType(Command.TYPE_POSITION_PERIODIC); verifyCommand(encoder, command, binary("242434000b5800383a00050005781d0d")); } -- cgit v1.2.3 From ed3950fbdccfbd118ed898066fc74c93e7542ec4 Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 29 Aug 2023 16:13:47 +0400 Subject: Fix content size for encoding --- src/main/java/org/traccar/protocol/GatorProtocolEncoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java index 4a3e21d85..895c68af5 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -91,7 +91,7 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { String[] data = command.getString(Command.KEY_FREQUENCY).split(";"); content.writeShort(Integer.valueOf(data[0])); content.writeShort(Integer.valueOf(data[1])); - content.writeShort(Integer.valueOf(data[2])); + content.writeByte(Integer.valueOf(data[2])); return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_PERIODIC, content); default: return null; -- cgit v1.2.3 From 63ea08a14e381261568192a999f51e8c3cc3f574 Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 29 Aug 2023 17:09:18 +0400 Subject: Undo formatting changes in Command.java --- src/main/java/org/traccar/model/Command.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index 900436a01..99988dd82 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -15,8 +15,9 @@ */ package org.traccar.model; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.traccar.storage.QueryIgnore; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.traccar.storage.StorageName; @StorageName("tc_commands") @@ -71,7 +72,6 @@ public class Command extends BaseCommand { public static final String KEY_UNIQUE_ID = "uniqueId"; public static final String KEY_FREQUENCY = "frequency"; - public static final String KEY_LANGUAGE = "language"; public static final String KEY_TIMEZONE = "timezone"; public static final String KEY_DEVICE_PASSWORD = "devicePassword"; -- cgit v1.2.3 From f6f210592413157006776ba454d29834e167688c Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 29 Aug 2023 17:29:30 +0400 Subject: - Set supported commands in one call - Remove timing interval command - Rename messages according to codebase standard --- src/main/java/org/traccar/protocol/GatorProtocol.java | 12 ++++++------ .../org/traccar/protocol/GatorProtocolDecoder.java | 9 ++++----- .../org/traccar/protocol/GatorProtocolEncoder.java | 19 ++++++------------- .../traccar/protocol/GatorProtocolEncoderTest.java | 13 ------------- 4 files changed, 16 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index 0f44fbf47..e6793875b 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -28,12 +28,12 @@ public class GatorProtocol extends BaseProtocol { @Inject public GatorProtocol(Config config) { - setSupportedDataCommands(Command.TYPE_POSITION_SINGLE); - setSupportedDataCommands(Command.TYPE_ENGINE_RESUME); - setSupportedDataCommands(Command.TYPE_ENGINE_STOP); - setSupportedDataCommands(Command.TYPE_POSITION_PERIODIC); - setSupportedDataCommands(Command.TYPE_SET_SPEED_LIMIT); - setSupportedDataCommands(Command.TYPE_SET_ODOMETER); + 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 0202ed7d0..53b8909be 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -38,11 +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_POSITION_PERIODIC = 0x34; - public static final int MSG_SET_SPEED_LIMIT = 0x3F; - public static final int MSG_SET_ODOMETER = 0x6B; - public static final int MSG_RESTORES_THE_OIL_DUCT = 0x38; - public static final int MSG_CLOSE_THE_OIL_DUCT = 0x39; + 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 895c68af5..6c6b9a54a 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -51,8 +51,7 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { buf.writeByte(type); buf.writeByte(0x00); - // ip 4 bytes, content length, checksum and end byte - buf.writeByte(4 + 1 + (content != null ? content.readableBytes() : 0) + 1); + buf.writeByte(4 + 1 + (content != null ? content.readableBytes() : 0) + 1); // length ByteBuf pseudoIPAddress = encodeId(deviceId); buf.writeBytes(pseudoIPAddress); @@ -76,23 +75,17 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder { switch (command.getType()) { case Command.TYPE_POSITION_SINGLE: - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST, content); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST, null); case Command.TYPE_ENGINE_STOP: - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_THE_OIL_DUCT, content); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_OIL_DUCT, null); case Command.TYPE_ENGINE_RESUME: - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESTORES_THE_OIL_DUCT, content); + 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_SET_SPEED_LIMIT, content); + 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_SET_ODOMETER, content); - case Command.TYPE_POSITION_PERIODIC: - String[] data = command.getString(Command.KEY_FREQUENCY).split(";"); - content.writeShort(Integer.valueOf(data[0])); - content.writeShort(Integer.valueOf(data[1])); - content.writeByte(Integer.valueOf(data[2])); - return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_PERIODIC, content); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_OVERSPEED_ALARM, content); default: return null; } diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java index 1559e8294..af6c71e37 100644 --- a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java @@ -20,17 +20,4 @@ public class GatorProtocolEncoderTest extends ProtocolTest { command.setType(Command.TYPE_POSITION_SINGLE); verifyCommand(encoder, command, binary("24243000062008958C070D")); } - - @Test - public void testEncodePeriodicPositionRetrievalIntervalSet() throws Exception { - var encoder = inject(new GatorProtocolEncoder(null)); - var device = encoder.getCacheManager().getObject(Device.class, 1); - when(device.getUniqueId()).thenReturn("13088005658"); - - Command command = new Command(); - command.setDeviceId(1); - command.set(command.KEY_FREQUENCY, "5;5;120"); - command.setType(Command.TYPE_POSITION_PERIODIC); - verifyCommand(encoder, command, binary("242434000b5800383a00050005781d0d")); - } } -- cgit v1.2.3 From eaacc24b7461efc6f939efcf7ecc17ae646b13a5 Mon Sep 17 00:00:00 2001 From: seym45 Date: Tue, 29 Aug 2023 17:41:06 +0400 Subject: Undo import order --- src/main/java/org/traccar/protocol/GatorProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index 53b8909be..a9c620090 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BcdUtil; @@ -26,7 +27,6 @@ import org.traccar.helper.Checksum; import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import org.traccar.session.DeviceSession; import java.net.SocketAddress; -- cgit v1.2.3 From b56282ad98038df6098c8ca2014cb5516be5a7fc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 30 Aug 2023 06:47:21 -0700 Subject: Fix missing time --- .../org/traccar/protocol/Minifinder2ProtocolDecoder.java | 15 +++------------ .../traccar/protocol/Minifinder2ProtocolDecoderTest.java | 3 +++ 2 files changed, 6 insertions(+), 12 deletions(-) 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 positions = new LinkedList<>(); Set 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/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); -- cgit v1.2.3 From b735b834755039ef54524db0f1de4484d17dec22 Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Wed, 30 Aug 2023 23:55:13 +0300 Subject: correction: - used key for fields 38-44 --- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 51b7db763..406a0292c 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -291,11 +291,11 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 42: case 43: value = buf.readUnsignedShortLE(); - position.set("fuel" + (j + 2 - 38), (value < 65500) ? value : null); + position.set(Position.KEY_FUEL_LEVEL + (j + 2 - 38), (value < 65500) ? value : null); break; case 44: value = buf.readUnsignedShortLE(); - position.set("fuel", (value < 65500) ? value : null); + position.set(Position.KEY_FUEL_LEVEL, (value < 65500) ? value : null); break; case 45: case 46: -- cgit v1.2.3 From 987e2f9192ac3d0381235335b44f35ed83f78a3f Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Thu, 31 Aug 2023 00:00:52 +0300 Subject: correction: - fix for checkstyle --- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 406a0292c..2e857b212 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -291,7 +291,8 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 42: case 43: value = buf.readUnsignedShortLE(); - position.set(Position.KEY_FUEL_LEVEL + (j + 2 - 38), (value < 65500) ? value : null); + position.set( + Position.KEY_FUEL_LEVEL + (j + 2 - 38), (value < 65500) ? value : null); break; case 44: value = buf.readUnsignedShortLE(); -- cgit v1.2.3 From 415f67418c510aa98a78883a1957a138c7313880 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Sep 2023 08:14:53 -0700 Subject: Fix tests --- tools/test-generator.py | 2 +- tools/test-integration.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/test-generator.py b/tools/test-generator.py index 20cecccf1..ed135b4aa 100755 --- a/tools/test-generator.py +++ b/tools/test-generator.py @@ -8,7 +8,7 @@ import time import random id = '123456789012345' -server = '49.13.29.182:5055' +server = 'localhost:5055' period = 1 step = 0.001 device_speed = 40 diff --git a/tools/test-integration.py b/tools/test-integration.py index 204fecb70..f31ad7a82 100755 --- a/tools/test-integration.py +++ b/tools/test-integration.py @@ -179,7 +179,7 @@ def send_message(port, message): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', port)) s.send(message.encode('ascii')) - time.sleep(0.5) + time.sleep(1.0) s.close() def get_protocols(cookie, device_id): -- cgit v1.2.3 From db12435e29bd611476b6516b9b9c115ca299afce Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Sep 2023 08:17:02 -0700 Subject: Update version number --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 06516794c..2e8b557ba 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.8", + "Implementation-Version": "5.9", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index f9988a6f3..9d9fbc73c 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.8 +AppVersion=5.9 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index ccd26d4e8..ae8c447cc 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.8", + "version": "5.9", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From 599494fed9953976d9b27f5319b6bcd8268b2f48 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Sep 2023 13:07:09 -0700 Subject: Update git submodule --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index f8048106d..9bd75b29e 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit f8048106dacb36466ae221a8258da85f35db6e9d +Subproject commit 9bd75b29e3654e0854e3ae35741609dd24ceb218 -- cgit v1.2.3 From 6d8061f868ca142018581d38410dcff80256c9cd Mon Sep 17 00:00:00 2001 From: David Bergh Date: Thu, 7 Sep 2023 16:13:12 +0200 Subject: Add Meitrack WiFi Aps, celltowers and network info Includes WiFi aps, celltowers and network information. Based on page 8-10 of Meitrack protocol: https://www.meitrack.com/cd-download/Protocols/MEITRACK_P88L_GPRS_Protocol.pdf Closes #5171 --- .../traccar/protocol/MeitrackProtocolDecoder.java | 40 ++++++++++++++++++++++ .../protocol/MeitrackProtocolDecoderTest.java | 8 +++++ 2 files changed, 48 insertions(+) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 0f0d22021..eb0a80e05 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -16,6 +16,7 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; @@ -30,6 +31,7 @@ import org.traccar.helper.UnitsConverter; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; @@ -394,6 +396,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); + Network network = new Network(); + buf.readUnsignedShortLE(); // length buf.readUnsignedShortLE(); // index @@ -537,6 +541,32 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { int id = extension ? buf.readUnsignedShort() : buf.readUnsignedByte(); int length = buf.readUnsignedByte(); switch (id) { + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + String wifiMAC = ByteBufUtil.hexDump(buf.readSlice(6)); + int wifiRSSI = buf.readUnsignedShortLE(); + network.addWifiAccessPoint(WifiAccessPoint.from(wifiMAC, wifiRSSI)); + break; + case 0x0E: + case 0x0F: + case 0x10: + case 0x12: + case 0x13: + int stationMCC = buf.readUnsignedShortLE(); + int stationMNC = buf.readUnsignedShortLE(); + int stationLAC = buf.readUnsignedShortLE(); + long stationID = buf.readUnsignedIntLE(); + int stationRX_LEVEL = buf.readUnsignedShortLE(); + network.addCellTower(CellTower.from(stationMCC, stationMNC, stationLAC, stationID, + stationRX_LEVEL)); + break; case 0x2A: case 0x2B: case 0x2C: @@ -548,6 +578,13 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // label position.set(Position.PREFIX_TEMP + (id - 0x2A), buf.readShortLE() * 0.01); break; + case 0x4B: + position.set("networkVersion", buf.readUnsignedByte()); + position.set("networkType", buf.readUnsignedByte()); + int networkDescLen = buf.readUnsignedByte(); + String networkDesc = buf.readSlice(networkDescLen).toString(StandardCharsets.US_ASCII); + network.setRadioType(networkDesc); + break; case 0xFE31: buf.readUnsignedByte(); // alarm protocol buf.readUnsignedByte(); // alarm type @@ -570,6 +607,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { } } + if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { + position.setNetwork(network); + } positions.add(position); } diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 8d2aee501..d786021f1 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -15,6 +15,14 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { "2424683136342C3836363334343035333039353238322C4343452C000000000100820018000505000600070B14001500080800000900000A00000B00001606001A0000402300FE90000006022E79570103E55CCC0604E1FDB32B0CC32C00000D58EB02001C01000000050E0CCC010000B627BF11000000004B1001010D475052532847534D2039303029FEA50601FFFFFF7FFFFEA80701010258023800FEB20501010000002A41360D0A"), "battery2Level", 88); + verifyAttribute(decoder, binary( + "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a"), + "networkVersion", 1); + + verifyAttribute(decoder, binary( + "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a"), + "networkType", 1); + verifyAttribute(decoder, binary( "2424593434312c3836353431333035303839313733372c4343452c00000000030088001800050501061607191400150008080000098e000a05000b0c001608001a0000402300fe9000000602c3fe5ffe03e22a1f0904e6688d2b0cd94002000d5f6f03001c01000000050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000083001700050501061607191400150008080000098e000a05000b0c001608001a0000405100fe9000000502c3fe5ffe03e22a1f0904e6688d2b0cd94002000d606f0300050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000088001800050501061607151400150008080000098e000a05000b0c001607001a0000402300fe9000000602c3fe5ffe03e22a1f0904f0688d2b0cd94002000d696f03001c01000000050e0cf901010032700298c80897ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501000000002a36320d0a"), Position.KEY_BATTERY_LEVEL, 77); -- cgit v1.2.3 From bb46ff66b74731dd7c7b2359017b0cd8c137824c Mon Sep 17 00:00:00 2001 From: David Bergh Date: Fri, 8 Sep 2023 15:30:47 +0200 Subject: Use signed short for RSSI --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index eb0a80e05..3ee9d9732 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -551,7 +551,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x24: case 0x25: String wifiMAC = ByteBufUtil.hexDump(buf.readSlice(6)); - int wifiRSSI = buf.readUnsignedShortLE(); + int wifiRSSI = buf.readShortLE(); network.addWifiAccessPoint(WifiAccessPoint.from(wifiMAC, wifiRSSI)); break; case 0x0E: @@ -563,7 +563,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { int stationMNC = buf.readUnsignedShortLE(); int stationLAC = buf.readUnsignedShortLE(); long stationID = buf.readUnsignedIntLE(); - int stationRX_LEVEL = buf.readUnsignedShortLE(); + int stationRX_LEVEL = buf.readShortLE(); network.addCellTower(CellTower.from(stationMCC, stationMNC, stationLAC, stationID, stationRX_LEVEL)); break; -- cgit v1.2.3 From 22625690090a91e452f7b828e787330e7fce8f70 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 8 Sep 2023 08:06:09 -0700 Subject: Add DTCs spacing --- src/main/java/org/traccar/protocol/CastelProtocolDecoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java index 566d856bb..b076b9f66 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java @@ -449,6 +449,7 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { } else { codes.append(ObdDecoder.decodeCode(buf.readUnsignedShortLE())); } + codes.append(' '); } position.set(Position.KEY_DTCS, codes.toString().trim()); -- cgit v1.2.3 From 1ae9886ad10edcbc876a5295021f86bb7e534fde Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 9 Sep 2023 11:21:53 -0700 Subject: Implement NTO protocol --- setup/default.xml | 1 + .../java/org/traccar/protocol/NtoProtocol.java | 42 +++++++++++ .../org/traccar/protocol/NtoProtocolDecoder.java | 82 ++++++++++++++++++++++ .../traccar/protocol/NtoProtocolDecoderTest.java | 19 +++++ 4 files changed, 144 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/NtoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/NtoProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/NtoProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index a66866597..7652ff75f 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -291,5 +291,6 @@ 5247 5248 5249 + 5250 diff --git a/src/main/java/org/traccar/protocol/NtoProtocol.java b/src/main/java/org/traccar/protocol/NtoProtocol.java new file mode 100644 index 000000000..d3596e287 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NtoProtocol.java @@ -0,0 +1,42 @@ +/* + * 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.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class NtoProtocol extends BaseProtocol { + + @Inject + public NtoProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '&')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new NtoProtocolDecoder(NtoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java b/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java new file mode 100644 index 000000000..bbdae485e --- /dev/null +++ b/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java @@ -0,0 +1,82 @@ +/* + * 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.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class NtoProtocolDecoder extends BaseProtocolDecoder { + + public NtoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("^NB,") // manufacturer + .number("(d+),") // imei + .expression("(...),") // type + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AVM]),") // validity + .number("([NS]),(dd)(dd.d+),") // latitude + .number("([EW]),(ddd)(dd.d+),") // longitude + .number("(d+.?d*),") // speed + .number("(d+),") // course + .number("(x+),") // status + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_TYPE, parser.next()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextInt()); + + position.set(Position.KEY_STATUS, parser.next()); + + return position; + } + +} diff --git a/src/test/java/org/traccar/protocol/NtoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NtoProtocolDecoderTest.java new file mode 100644 index 000000000..424eaadde --- /dev/null +++ b/src/test/java/org/traccar/protocol/NtoProtocolDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class NtoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new NtoProtocolDecoder(null)); + + verifyPosition(decoder, text( + "^NB,880002023090601,N00,050923,233519,V,N,2236.1994,E,11315.4645,5,0,000000000000,460:00:0:75217090,-04:00,,1693971319,31,2DA5"), + position("2023-09-05 23:35:19.000", false, 22.60332, 113.25774)); + + } + +} -- cgit v1.2.3 From 2dcc3e0ee0ac637ca85e2457dc3d12c4edc01ec4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 9 Sep 2023 11:58:57 -0700 Subject: Add RAMAC Multievent Callback --- setup/default.xml | 1 + .../java/org/traccar/protocol/RamacProtocol.java | 42 +++++++++ .../org/traccar/protocol/RamacProtocolDecoder.java | 99 ++++++++++++++++++++++ .../traccar/protocol/SigfoxProtocolDecoder.java | 2 +- .../traccar/protocol/RamacProtocolDecoderTest.java | 26 ++++++ 5 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/traccar/protocol/RamacProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RamacProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/RamacProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index 7652ff75f..c5992b087 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -292,5 +292,6 @@ 5248 5249 5250 + 5251 diff --git a/src/main/java/org/traccar/protocol/RamacProtocol.java b/src/main/java/org/traccar/protocol/RamacProtocol.java new file mode 100644 index 000000000..42ce16fe8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RamacProtocol.java @@ -0,0 +1,42 @@ +/* + * 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.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class RamacProtocol extends BaseProtocol { + + @Inject + public RamacProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new RamacProtocolDecoder(RamacProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java b/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java new file mode 100644 index 000000000..ffe04a298 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java @@ -0,0 +1,99 @@ +/* + * 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.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +public class RamacProtocolDecoder extends BaseHttpProtocolDecoder { + + private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public RamacProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String content = request.content().toString(StandardCharsets.UTF_8); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + String deviceId = json.getString("DeviceId"); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_TYPE, json.getInt("PacketType")); + position.set(Position.KEY_INDEX, json.getInt("SeqNumber")); + position.setDeviceTime(dateFormat.parse(json.getString("UpdateDate"))); + + int alert = json.getInt("Alert"); + if (alert > 0) { + position.set("alert", alert); + String alertMessage = json.getString("AlertMessage"); + if (!alertMessage.isEmpty()) { + position.set("alertMessage", alertMessage); + } + } + + if (json.containsKey("Event")) { + position.set(Position.KEY_EVENT, json.getInt("Event")); + } + + position.set("deviceType", json.getString("DeviceTypeText")); + + if (json.containsKey("Latitude") && json.containsKey("Longitude")) { + position.setValid(true); + if (json.containsKey("LocationDateTime")) { + position.setFixTime(dateFormat.parse(json.getString("LocationDateTime"))); + } else { + position.setFixTime(position.getDeviceTime()); + } + position.setLatitude(json.getJsonNumber("Latitude").doubleValue()); + position.setLongitude(json.getJsonNumber("Longitude").doubleValue()); + } else { + getLastLocation(position, position.getDeviceTime()); + } + + sendResponse( + channel, HttpResponseStatus.OK, + Unpooled.copiedBuffer("{\"CaseID\":1,\"EventID\":1}", StandardCharsets.UTF_8)); + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index 1298112d1..6f739a1a4 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -105,7 +105,7 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { FullHttpRequest request = (FullHttpRequest) msg; String content = request.content().toString(StandardCharsets.UTF_8); if (!content.startsWith("{")) { - content = URLDecoder.decode(content.split("=")[0], "UTF-8"); + content = URLDecoder.decode(content.split("=")[0], StandardCharsets.UTF_8); } JsonObject json = Json.createReader(new StringReader(content)).readObject(); diff --git a/src/test/java/org/traccar/protocol/RamacProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RamacProtocolDecoderTest.java new file mode 100644 index 000000000..86734a259 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RamacProtocolDecoderTest.java @@ -0,0 +1,26 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class RamacProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new RamacProtocolDecoder(null)); + + verifyAttributes(decoder, request(HttpMethod.POST, "/", + buffer("{\"PacketType\": 0,\"SeqNumber\": 4,\"UpdateDate\": \"2022-05-06 12:25:35\",\"Alert\": 42,\"AlertMessage\": \"Low Battery\",\"Mode\": 1,\"ModeText\": \"Help Me\",\"SigfoxTXInterval\": 2,\"GpsFixInterval\": 3,\"SigfoxTXIntervalText\": \"2 Seconds\",\"GpsFixIntervalText\": \"3 Seconds\",\"BatteryPercentage\": 4,\"Battery\": 0.1,\"Temperature\": -22,\"HwVersion\": 7,\"FirmwareVersion\": 8,\"DeviceId\": \"A10001\",\"DeviceType\": \"12\",\"DeviceTypeText\": \"RAMAC P1\"}"))); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"PacketType\": 1,\"SeqNumber\": 4,\"UpdateDate\": \"2022-05-06 12:25:35\",\"Alert\": 0,\"AlertMessage\": \"\",\"Latitude\": -25.87586735939189,\"Longitude\": 28.179579268668846,\"Speed\": 1,\"COG\": 3,\"EstimatedAccuracy\": 3,\"LastLocation\": 0,\"LastLocationText\": \"NEW LOCATION\",\"IsMoving\": 0,\"IsMovingText\": \"STATIONARY\",\"GpsEvent\": 5,\"GpsEventText\": \"Heartbeat\",\"DeviceId\": \"A10001\",\"DeviceType\": \"12\",\"DeviceTypeText\": \"RAMAC P1\"}"))); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"PacketType\": 2,\"SeqNumber\": 4,\"UpdateDate\": \"2022-05-06 12:25:35\",\"Alert\": 19,\"AlertMessage\": \"P1 Panic\",\"Event\": 16,\"DeviceId\": \"A10001\",\"DeviceType\": \"12\",\"DeviceTypeText\": \"RAMAC P1\",\"Latitude\": -25.875867359392,\"Longitude\": 28.179579268669,\"LocationDateTime\": \"2022-05-05 08:48:11\"}"))); + + } + +} -- cgit v1.2.3 From 023ab3249c1cbeb89e44af0d9f6c98130519a67d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 9 Sep 2023 19:09:54 -0700 Subject: Add missing Ramac attributes --- .../java/org/traccar/protocol/RamacProtocolDecoder.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java b/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java index ffe04a298..ffdc68474 100644 --- a/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java @@ -71,9 +71,22 @@ public class RamacProtocolDecoder extends BaseHttpProtocolDecoder { } } + if (json.containsKey("GpsEvent")) { + position.set("gpsEvent", json.getInt("GpsEvent")); + if (json.containsKey("GpsEventText")) { + position.set("gpsEventText", json.getString("GpsEventText")); + } + } + if (json.containsKey("Event")) { position.set(Position.KEY_EVENT, json.getInt("Event")); } + if (json.containsKey("BatteryPercentage")) { + position.set(Position.KEY_BATTERY_LEVEL, json.getInt("BatteryPercentage")); + } + if (json.containsKey("Battery")) { + position.set(Position.KEY_BATTERY, json.getJsonNumber("Battery").doubleValue()); + } position.set("deviceType", json.getString("DeviceTypeText")); -- cgit v1.2.3 From 33f0df11d027a48be2c3c1030198855311e13d00 Mon Sep 17 00:00:00 2001 From: David Bergh Date: Mon, 11 Sep 2023 09:20:38 +0200 Subject: Reformat MAC + inline --- .../java/org/traccar/protocol/MeitrackProtocolDecoder.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 3ee9d9732..0b17b3ee7 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -550,7 +550,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x23: case 0x24: case 0x25: - String wifiMAC = ByteBufUtil.hexDump(buf.readSlice(6)); + String wifiMAC = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); int wifiRSSI = buf.readShortLE(); network.addWifiAccessPoint(WifiAccessPoint.from(wifiMAC, wifiRSSI)); break; @@ -559,13 +559,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x10: case 0x12: case 0x13: - int stationMCC = buf.readUnsignedShortLE(); - int stationMNC = buf.readUnsignedShortLE(); - int stationLAC = buf.readUnsignedShortLE(); - long stationID = buf.readUnsignedIntLE(); - int stationRX_LEVEL = buf.readShortLE(); - network.addCellTower(CellTower.from(stationMCC, stationMNC, stationLAC, stationID, - stationRX_LEVEL)); + network.addCellTower(CellTower.from(buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), + buf.readUnsignedShortLE(), buf.readUnsignedIntLE(), buf.readShortLE())); break; case 0x2A: case 0x2B: @@ -582,8 +577,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { position.set("networkVersion", buf.readUnsignedByte()); position.set("networkType", buf.readUnsignedByte()); int networkDescLen = buf.readUnsignedByte(); - String networkDesc = buf.readSlice(networkDescLen).toString(StandardCharsets.US_ASCII); - network.setRadioType(networkDesc); + network.setRadioType(buf.readSlice(networkDescLen).toString(StandardCharsets.US_ASCII)); break; case 0xFE31: buf.readUnsignedByte(); // alarm protocol -- cgit v1.2.3 From e000421d9e67960d28666471bf8ea8c7b629dd9d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 11 Sep 2023 21:52:13 -0700 Subject: Add speed limit accuracy (fix #5175) --- src/main/java/org/traccar/MainModule.java | 2 +- src/main/java/org/traccar/config/Keys.java | 8 ++++++++ .../java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java | 9 ++++++--- .../org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java | 4 +++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 6ed240d2c..9559b3a90 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -303,7 +303,7 @@ public class MainModule extends AbstractModule { switch (type) { case "overpass": default: - return new OverpassSpeedLimitProvider(client, url); + return new OverpassSpeedLimitProvider(config, client, url); } } return null; diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 27f5f0921..23a983e7b 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1677,6 +1677,14 @@ public final class Keys { "speedLimit.url", List.of(KeyType.CONFIG)); + /** + * Search radius for speed limit. Value is in meters. Default value is 100. + */ + public static final ConfigKey SPEED_LIMIT_ACCURACY = new IntegerConfigKey( + "speedLimit.accuracy", + List.of(KeyType.CONFIG), + 100); + /** * Override latitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can be * N for North or S for South. diff --git a/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java b/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java index 60ad65f9e..a25eedb2c 100644 --- a/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java +++ b/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.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. @@ -15,6 +15,8 @@ */ package org.traccar.speedlimit; +import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; import jakarta.json.JsonArray; @@ -28,9 +30,10 @@ public class OverpassSpeedLimitProvider implements SpeedLimitProvider { private final Client client; private final String url; - public OverpassSpeedLimitProvider(Client client, String url) { + public OverpassSpeedLimitProvider(Config config, Client client, String url) { + int accuracy = config.getInteger(Keys.SPEED_LIMIT_ACCURACY); this.client = client; - this.url = url + "?data=[out:json];way[maxspeed](around:100.0,%f,%f);out%%20tags;"; + this.url = url + "?data=[out:json];way[maxspeed](around:" + accuracy + ",%f,%f);out%%20tags;"; } private Double parseSpeed(String value) { diff --git a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java index a59d1ce91..dbdf85420 100644 --- a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java +++ b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; +import org.traccar.config.Config; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; @@ -16,7 +17,8 @@ public class OverpassSpeedLimitProviderTest { @Disabled @Test public void testOverpass() throws Exception { - SpeedLimitProvider provider = new OverpassSpeedLimitProvider(client, "http://8.8.8.8/api/interpreter"); + var config = new Config(); + SpeedLimitProvider provider = new OverpassSpeedLimitProvider(config, client, "http://8.8.8.8/api/interpreter"); provider.getSpeedLimit(34.74767, -82.48098, new SpeedLimitProvider.SpeedLimitProviderCallback() { @Override -- cgit v1.2.3 From 2b2eb27834968addc35ec3e4be1be88a0f8806ac Mon Sep 17 00:00:00 2001 From: David Bergh Date: Tue, 12 Sep 2023 07:26:18 +0200 Subject: Skip network --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 0b17b3ee7..2e786070f 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -574,10 +574,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + (id - 0x2A), buf.readShortLE() * 0.01); break; case 0x4B: - position.set("networkVersion", buf.readUnsignedByte()); - position.set("networkType", buf.readUnsignedByte()); - int networkDescLen = buf.readUnsignedByte(); - network.setRadioType(buf.readSlice(networkDescLen).toString(StandardCharsets.US_ASCII)); + buf.skipBytes(length); // network information break; case 0xFE31: buf.readUnsignedByte(); // alarm protocol -- cgit v1.2.3 From df28582395349cfc71cfdea1baf1a7683f804110 Mon Sep 17 00:00:00 2001 From: David Bergh Date: Wed, 13 Sep 2023 10:50:59 +0200 Subject: Fix mac address formatting --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 2e786070f..8a1e14834 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -550,9 +550,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x23: case 0x24: case 0x25: - String wifiMAC = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); - int wifiRSSI = buf.readShortLE(); - network.addWifiAccessPoint(WifiAccessPoint.from(wifiMAC, wifiRSSI)); + String wifiMac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); + network.addWifiAccessPoint(WifiAccessPoint.from(wifiMac.substring(0, wifiMac.length() - 1), + buf.readShortLE())); break; case 0x0E: case 0x0F: -- cgit v1.2.3 From 51a904228bd33d30db53717b65ddc071f660ab1b Mon Sep 17 00:00:00 2001 From: David Bergh Date: Wed, 13 Sep 2023 10:56:45 +0200 Subject: Replace network information tests --- .../java/org/traccar/protocol/MeitrackProtocolDecoderTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index d786021f1..a4b9c696c 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -15,13 +15,11 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { "2424683136342C3836363334343035333039353238322C4343452C000000000100820018000505000600070B14001500080800000900000A00000B00001606001A0000402300FE90000006022E79570103E55CCC0604E1FDB32B0CC32C00000D58EB02001C01000000050E0CCC010000B627BF11000000004B1001010D475052532847534D2039303029FEA50601FFFFFF7FFFFEA80701010258023800FEB20501010000002A41360D0A"), "battery2Level", 88); - verifyAttribute(decoder, binary( - "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a"), - "networkVersion", 1); + verifyPositions(decoder, binary( + "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a")); - verifyAttribute(decoder, binary( - "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a"), - "networkType", 1); + verifyPositions(decoder, binary( + "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a")); verifyAttribute(decoder, binary( "2424593434312c3836353431333035303839313733372c4343452c00000000030088001800050501061607191400150008080000098e000a05000b0c001608001a0000402300fe9000000602c3fe5ffe03e22a1f0904e6688d2b0cd94002000d5f6f03001c01000000050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000083001700050501061607191400150008080000098e000a05000b0c001608001a0000405100fe9000000502c3fe5ffe03e22a1f0904e6688d2b0cd94002000d606f0300050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000088001800050501061607151400150008080000098e000a05000b0c001607001a0000402300fe9000000602c3fe5ffe03e22a1f0904f0688d2b0cd94002000d696f03001c01000000050e0cf901010032700298c80897ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501000000002a36320d0a"), -- cgit v1.2.3 From 2ac6fb3f0d6827733724d3d483d87a3ace0b839f Mon Sep 17 00:00:00 2001 From: David Bergh Date: Wed, 13 Sep 2023 11:00:17 +0200 Subject: Remove identical test --- src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index a4b9c696c..91dcf0386 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -18,9 +18,6 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, binary( "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a")); - verifyPositions(decoder, binary( - "2424533232312c3836323331313036323737393431362c4343452c000000000100bb001c0006012305000600071f1500fe6961050800000900000a00000b00001aca000702a72c52030340a0c90004f3408b2c0ca80100000d238d08001c01000000fe37000000000a0e0cf00001002700167aa601a0ff1d082abd890a491cd2ff1e0828bd890a491cd2ff1f0842490f526db0caff20083c286d5b082cc9ff21083e286d5b082cc9ff2208ac233fc0d2e0c7ff2308b0411d64d9d5c7ff2408ae233fc0d496c3ff4b150101124c54452845555452414e2d42414e443230292a38420d0a")); - verifyAttribute(decoder, binary( "2424593434312c3836353431333035303839313733372c4343452c00000000030088001800050501061607191400150008080000098e000a05000b0c001608001a0000402300fe9000000602c3fe5ffe03e22a1f0904e6688d2b0cd94002000d5f6f03001c01000000050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000083001700050501061607191400150008080000098e000a05000b0c001608001a0000405100fe9000000502c3fe5ffe03e22a1f0904e6688d2b0cd94002000d606f0300050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000088001800050501061607151400150008080000098e000a05000b0c001607001a0000402300fe9000000602c3fe5ffe03e22a1f0904f0688d2b0cd94002000d696f03001c01000000050e0cf901010032700298c80897ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501000000002a36320d0a"), Position.KEY_BATTERY_LEVEL, 77); -- cgit v1.2.3 From 6b61074e00ea242dbe2135423f75ab44473563a2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 13 Sep 2023 06:50:46 -0700 Subject: Fix formatting --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 8a1e14834..aa0fe19d8 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -551,16 +551,17 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x24: case 0x25: String wifiMac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); - network.addWifiAccessPoint(WifiAccessPoint.from(wifiMac.substring(0, wifiMac.length() - 1), - buf.readShortLE())); + network.addWifiAccessPoint(WifiAccessPoint.from( + wifiMac.substring(0, wifiMac.length() - 1), buf.readShortLE())); break; case 0x0E: case 0x0F: case 0x10: case 0x12: case 0x13: - network.addCellTower(CellTower.from(buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), - buf.readUnsignedShortLE(), buf.readUnsignedIntLE(), buf.readShortLE())); + network.addCellTower(CellTower.from( + buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), + buf.readUnsignedShortLE(), buf.readUnsignedIntLE(), buf.readShortLE())); break; case 0x2A: case 0x2B: -- cgit v1.2.3 From 070cb02751a29eb746a5b2c1797dcbe26e5af9ad Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 14 Sep 2023 18:30:37 -0700 Subject: Split MD500S OBD odometer --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index aa0fe19d8..506ad2179 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -514,7 +514,6 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { position.setTime(new Date((946684800 + buf.readUnsignedIntLE()) * 1000)); // 2000-01-01 break; case 0x0C: - case 0x9B: position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); break; case 0x0D: @@ -523,6 +522,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x25: position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE())); break; + case 0x9B: + position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedIntLE()); + break; case 0xA0: position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE() * 0.001); break; -- cgit v1.2.3 From 7ce4fb9a628f1875ee7b616bbd3a03a6be008a0d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 19 Sep 2023 06:30:29 -0700 Subject: Handle long odometer values --- src/main/java/org/traccar/protocol/StartekProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java index 9c749c8d9..5cfbb36ca 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -178,7 +178,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { position.setCourse(parser.nextInt()); position.setAltitude(parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextLong()); position.setNetwork(new Network(CellTower.from( parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), parser.nextInt()))); diff --git a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java index 9b1362f5d..94b3fd256 100644 --- a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class StartekProtocolDecoderTest extends ProtocolTest { var decoder = inject(new StartekProtocolDecoder(null)); + verifyPosition(decoder, text( + "&&l141,863911061945394,000,0,,230918072531,A,22.678598,114.045970,26,0.6,0,0,74,2286304571,460|0|249F|00001093,20,001C,00,00,04A7|019C|0000|0000,1,C0")); + verifyAttribute(decoder, text( "&&s148,868703050178631,000,37,,230704040211,A,22.678565,114.046011,31,0.5,0,339,77,8,460|0|249F|0AC2620D,27,0000001D,02,00,04F2|01A1|0000|0000,129,,,,949037"), Position.KEY_HOURS, 9490000L); -- cgit v1.2.3 From a9c311855a495901935c2cb70252fa917fd88232 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 20 Sep 2023 07:46:27 -0700 Subject: Fix PUI date format --- src/main/java/org/traccar/protocol/PuiProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java b/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java index a80af65fb..f10ff3fe7 100644 --- a/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java @@ -51,7 +51,7 @@ public class PuiProtocolDecoder extends BaseMqttProtocolDecoder { position.setValid(true); - DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss.SSS'Z'"); + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); position.setTime(dateFormat.parse(json.getString("ts"))); JsonObject location = json.getJsonObject("location"); diff --git a/src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java index 41568d0c1..1bbf17361 100644 --- a/src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java @@ -16,7 +16,7 @@ public class PuiProtocolDecoderTest extends ProtocolTest { "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()); + "{ \"id\": \"015262001044848\", \"ts\": \"2023-06-01T03:09:51.362Z\", \"rpt\": \"hf\", \"location\": { \"lat\": 33.91233, \"lon\": -84.20784 }, \"bear\": 70, \"spd\": 2482, \"ign\": \"on\" }")).qos(MqttQoS.EXACTLY_ONCE).messageId(1).build()); } -- cgit v1.2.3 From a8ea5f619cea8cc29289a91e3d4ac31a989759dd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 21 Sep 2023 21:05:32 -0700 Subject: Fix user deletion (fix #5183) --- src/main/java/org/traccar/api/resource/UserResource.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 587be014b..d73e8b6f5 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -122,7 +122,9 @@ public class UserResource extends BaseObjectResource { @DELETE public Response remove(@PathParam("id") long id) throws StorageException { Response response = super.remove(id); - request.getSession().removeAttribute(SessionResource.USER_ID_KEY); + if (getUserId() == id) { + request.getSession().removeAttribute(SessionResource.USER_ID_KEY); + } return response; } -- cgit v1.2.3 From d5bc3cc9d97be0df8e0ce46b000556efb08a9451 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 22 Sep 2023 07:35:44 -0700 Subject: Add NTO tracker alarms --- src/main/java/org/traccar/protocol/NtoProtocolDecoder.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java b/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java index bbdae485e..ba9ebd95d 100644 --- a/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java @@ -18,6 +18,7 @@ package org.traccar.protocol; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.Protocol; +import org.traccar.helper.BitUtil; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.model.Position; @@ -74,7 +75,16 @@ public class NtoProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(parser.nextDouble()); position.setCourse(parser.nextInt()); - position.set(Position.KEY_STATUS, parser.next()); + long status = parser.nextHexLong(); + position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_ALARM, BitUtil.check(status, 1) ? Position.ALARM_JAMMING : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 1) ? Position.ALARM_POWER_CUT : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 2) ? Position.ALARM_OVERSPEED : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 3) ? Position.ALARM_VIBRATION : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 4) ? Position.ALARM_GEOFENCE_ENTER : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 5) ? Position.ALARM_GEOFENCE_EXIT : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 4 * 8) ? Position.ALARM_LOW_BATTERY : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 4 * 8 + 4) ? Position.ALARM_DOOR : null); return position; } -- cgit v1.2.3 From 6f59f756a7d3e86924e762919dbbe13940a6511f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 22 Sep 2023 18:43:00 -0700 Subject: Fix TLW2-12BL ADC decoding --- src/main/java/org/traccar/protocol/T800xProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index 4ddea730c..a1093fc32 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -391,7 +391,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { for (int i = 1; i <= adcCount; i++) { String value = ByteBufUtil.hexDump(buf.readSlice(2)); if (!value.equals("ffff")) { - position.set(Position.PREFIX_ADC + i, Integer.parseInt(value) * 0.01); + position.set(Position.PREFIX_ADC + i, Integer.parseInt(value, 16) * 0.01); } } } diff --git a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java index 3f62a834c..468751e1b 100644 --- a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class T800xProtocolDecoderTest extends ProtocolTest { var decoder = inject(new T800xProtocolDecoder(null)); + verifyAttributes(decoder, binary( + "25251300594a1b0869738060144917003c0e101e03e85a2dc8c00005070000410000000000000000000000005b000003a5b45e00230919102252e3a5094288fabfc0e98b15420000010403921352ffff0000001cffffffffff25251300594a1c0869738060144917003c0e101e03e85a2ac7c00005070000410000000000000000000000002d000003a5b48b002309191023522d320642abfebfc0e98b15420000010c03921345ffff0000001bffffffffff25251300594a1d0869738060144917003c0e101e03e85a1ac9c000050700004100000000000000000000000024000003a5b4af00230919102452b81ef9410002c0c0ec8b15420108011403911345ffff0000001dffffffffff25251300594a1e0869738060144917003c0e101e03e85a3ec7c00005070000410000000000000000000000000e000003a5b4bd002309191025060ad7ec41da02c0c0058c15420084016303921345ffff0000001cffffffffff25251300594a1f0869738060144917003c0e101e03e85a3ec7c020050700004100000000000000000000000005000003a5b4c2002309191025090e2deb410203c0c0108c15420089014303921338ffff0000001dffffffffff25251300594a200869738060144917003c0e101e03e85a1ec5c000050700004100000000000000000000000020000003a5b4e20023091910260948e1bc412205c0c0458c15420040013603921355ffff0000001bffffffffff25251300594a210869738060144917003c0e101e03e85a00c5c020050700004100000000000000000000000000000003a5b4e20023091910270948e1bc412205c0c0458c15420040013603911332ffff0000001dffffffffff")); + verifyAttributes(decoder, binary( "272704004901380864112055585747c612230321220006000036435fc8acc2ee600f420000000000000000909019003900001356a18000012c0000a8c00000001e20d4800000c00000")); -- cgit v1.2.3 From 8638bc8ab98fa5ee6199ecaa28754972dee15e5e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 25 Sep 2023 20:55:21 -0700 Subject: Support HHD LoRa padlock --- .../org/traccar/protocol/HuabaoProtocolDecoder.java | 18 ++++++++++++++++-- .../traccar/protocol/HuabaoProtocolDecoderTest.java | 8 ++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index beb1ec41a..6e8373373 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -489,8 +489,22 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // reserved break; case 0x60: - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - buf.skipBytes(length - 2); + int event = buf.readUnsignedShort(); + position.set(Position.KEY_EVENT, event); + if (event >= 0x0061 && event <= 0x0066) { + buf.skipBytes(6); // lock id + stringValue = buf.readCharSequence(8, StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_DRIVER_UNIQUE_ID, stringValue); + } + break; + case 0x63: + for (int i = 1; i <= length / 11; i++) { + position.set("lock" + i + "Id", ByteBufUtil.hexDump(buf.readSlice(6))); + position.set("lock" + i + "Battery", buf.readUnsignedShort() * 0.001); + position.set("lock" + i + "Seal", buf.readUnsignedByte() == 0x31); + buf.readUnsignedByte(); // physical state + buf.readUnsignedByte(); // rssi + } break; case 0x69: position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 9c3fc164a..22c34c7ac 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -11,6 +11,14 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new HuabaoProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "7E020000C2000000001862003F0000000400108042015A322206C869480017007B012E230918081550661D01CC1A0000099DC25727B0130000099DC26B27B00100000C40F89427B0711438393836303436393130323139303037383135336A0114503FF8AF05826BC8CA24E124F732B7C780C5484D6318C0A840412262D4BCEC26CA0234CCB85455D5114F12B650FA841FBEC0B03C67A21F501CAE6C384595028DA76B010060110065000012345678903930303137333833630B0012345678900E5C3080006804000003D46902016F6D7E"), + Position.KEY_DRIVER_UNIQUE_ID, "\u00909001738"); + + verifyAttribute(decoder, binary( + "7e02000072440061018577001b0000100000200066005ffb8b065dc8900000000000002309080513406316cd91fe1314da1080318122c3a19a6f6f3a0fc6318113660b01fe00000a069a011704de690201a16a011f6b010a6c0f35313031303139313539323738373571143839363231303030313931353932373837353546407e"), + "lock2Battery", 4.038); + verifyNull(decoder, binary( "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e")); -- cgit v1.2.3 From 2e52618a0b122f226646dc48436ca7dc6ec8cc39 Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Tue, 26 Sep 2023 23:33:21 +0300 Subject: fix PR #4839: - before "case 5" delete blank line; - field 15 conversion to meters; - fields 53, 66 (check 15 bit, value 0-14 bits); - field 54 check negative, conversion to liters; - field 57 conversion to meters; - fields 207-255 fix field num check (I didn't compare the index correctly) --- .../protocol/NavtelecomProtocolDecoder.java | 33 +++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 2e857b212..9272b9e0b 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -196,9 +196,10 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { for (int j = 0; j < bits.length(); j++) { if (bits.get(j)) { + int bitNum = j + 1; int value; - switch (j + 1) { + switch (bitNum) { case 1: position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); break; @@ -216,7 +217,6 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { int guardMode = BitUtil.between(value, 3, 4); position.set(Position.KEY_ARMED, (0 < guardMode) && (guardMode < 3)); break; - case 5: value = buf.readUnsignedByte(); position.set(Position.KEY_ROAMING, BitUtil.check(value, 6) ? true : null); @@ -245,7 +245,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { position.setCourse(buf.readUnsignedShortLE()); break; case 15: - position.set(Position.KEY_ODOMETER, buf.readFloatLE()); + position.set(Position.KEY_ODOMETER, buf.readFloatLE() * 1000); break; case 19: position.set(Position.KEY_POWER, buf.readShortLE() * 0.001); @@ -313,15 +313,16 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 53: value = buf.readUnsignedShortLE(); if (value != 0x7FFF) { - if (BitUtil.check(value, 7)) { - position.set("obdFuelLevel", BitUtil.to(value, 6)); + if (BitUtil.check(value, 15)) { + position.set("obdFuelLevel", BitUtil.to(value, 14)); } else { - position.set("obdFuel", BitUtil.to(value, 6) / 10); + position.set("obdFuel", BitUtil.to(value, 14) / 10); } } break; case 54: - position.set(Position.KEY_FUEL_USED, buf.readFloatLE()); + double dValue = buf.readFloatLE() * 0.5; + position.set(Position.KEY_FUEL_USED, (dValue >= 0) ? (dValue * 0.5) : null); break; case 55: value = buf.readUnsignedShortLE(); @@ -332,7 +333,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_COOLANT_TEMP, (value != (byte) 0x80) ? value : null); break; case 57: - position.set(Position.KEY_OBD_ODOMETER, buf.readFloatLE()); + position.set(Position.KEY_OBD_ODOMETER, buf.readFloatLE() * 1000); break; case 58: case 59: @@ -357,10 +358,10 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 66: value = buf.readUnsignedShortLE(); if (value != 0x7FFF) { - if (BitUtil.check(value, 7)) { - position.set("obdAdBlueLevel", BitUtil.to(value, 6)); + if (BitUtil.check(value, 15)) { + position.set("obdAdBlueLevel", BitUtil.to(value, 14)); } else { - position.set("obdAdBlue", BitUtil.to(value, 6) / 10); + position.set("obdAdBlue", BitUtil.to(value, 14) / 10); } } break; @@ -407,16 +408,16 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { position.set("diagnostic", buf.readUnsignedIntLE()); break; default: - if ((207 <= j) && (j <= 222)) { + if ((207 <= bitNum) && (bitNum <= 222)) { position.set("user1Byte" + (j + 2 - 207), buf.readUnsignedByte()); - } else if ((223 <= j) && (j <= 237)) { + } else if ((223 <= bitNum) && (bitNum <= 237)) { position.set("user2Byte" + (j + 2 - 223), buf.readUnsignedShortLE()); - } else if ((238 <= j) && (j <= 252)) { + } else if ((238 <= bitNum) && (bitNum <= 252)) { position.set("user4Byte" + (j + 2 - 238), buf.readUnsignedIntLE()); - } else if ((253 <= j) && (j <= 255)) { + } else if ((253 <= bitNum) && (bitNum <= 255)) { position.set("user8Byte" + (j + 2 - 253), buf.readLongLE()); } else { - buf.skipBytes(getItemLength(j + 1)); + buf.skipBytes(getItemLength(bitNum)); } break; } -- cgit v1.2.3 From 2fbf2734f3d6d2dcd6dbb44eb92defb25e01671f Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Wed, 27 Sep 2023 23:29:32 +0300 Subject: fix after tests: - fields 53, 66 (fix for liters); - field 54 fix extra multiplier. --- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 9272b9e0b..1a64cedcb 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -316,13 +316,13 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 15)) { position.set("obdFuelLevel", BitUtil.to(value, 14)); } else { - position.set("obdFuel", BitUtil.to(value, 14) / 10); + position.set("obdFuel", BitUtil.to(value, 14) / 10.0); } } break; case 54: double dValue = buf.readFloatLE() * 0.5; - position.set(Position.KEY_FUEL_USED, (dValue >= 0) ? (dValue * 0.5) : null); + position.set(Position.KEY_FUEL_USED, (dValue >= 0) ? dValue : null); break; case 55: value = buf.readUnsignedShortLE(); @@ -361,7 +361,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 15)) { position.set("obdAdBlueLevel", BitUtil.to(value, 14)); } else { - position.set("obdAdBlue", BitUtil.to(value, 14) / 10); + position.set("obdAdBlue", BitUtil.to(value, 14) / 10.0); } } break; -- cgit v1.2.3 From cd179377a28b5d8e09e4f7304f6f5a03a6a05de2 Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Thu, 28 Sep 2023 22:30:23 +0300 Subject: minor edits: - j starts from 1; - fixed increments for all mentions of j. --- .../protocol/NavtelecomProtocolDecoder.java | 43 +++++++++++----------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 1a64cedcb..2dca220ed 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -193,13 +193,12 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - for (int j = 0; j < bits.length(); j++) { - if (bits.get(j)) { + for (int j = 1; j <= bits.length(); j++) { + if (bits.get(j - 1)) { - int bitNum = j + 1; int value; - switch (bitNum) { + switch (j) { case 1: position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); break; @@ -259,7 +258,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 24: case 25: case 26: - position.set(Position.PREFIX_ADC + (j + 2 - 21), buf.readUnsignedShortLE() * 0.001); + position.set(Position.PREFIX_ADC + (j + 1 - 21), buf.readUnsignedShortLE() * 0.001); break; case 29: value = buf.readUnsignedByte(); @@ -275,11 +274,11 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 33: case 34: - position.set(Position.PREFIX_COUNT + (j + 2 - 33), buf.readUnsignedIntLE()); + position.set(Position.PREFIX_COUNT + (j + 1 - 33), buf.readUnsignedIntLE()); break; case 35: case 36: - position.set("freq" + (j + 2 - 35), buf.readUnsignedShortLE()); + position.set("freq" + (j + 1 - 35), buf.readUnsignedShortLE()); break; case 37: position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); @@ -292,7 +291,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 43: value = buf.readUnsignedShortLE(); position.set( - Position.KEY_FUEL_LEVEL + (j + 2 - 38), (value < 65500) ? value : null); + Position.KEY_FUEL_LEVEL + (j + 1 - 38), (value < 65500) ? value : null); break; case 44: value = buf.readUnsignedShortLE(); @@ -308,7 +307,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 52: value = buf.readByte(); position.set( - Position.PREFIX_TEMP + (j + 2 - 45), (value != (byte) 0x80) ? value : null); + Position.PREFIX_TEMP + (j + 1 - 45), (value != (byte) 0x80) ? value : null); break; case 53: value = buf.readUnsignedShortLE(); @@ -341,7 +340,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 61: case 62: value = buf.readUnsignedShortLE(); - position.set("axleWeight" + (j + 2 - 58), (value != 0xFFFF) ? value : null); + position.set("axleWeight" + (j + 1 - 58), (value != 0xFFFF) ? value : null); break; case 63: value = buf.readUnsignedByte(); @@ -386,7 +385,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 81: case 82: case 83: - position.set("fuelTemp" + (j + 2 - 78), (int) buf.readByte()); + position.set("fuelTemp" + (j + 1 - 78), (int) buf.readByte()); break; case 163: case 164: @@ -394,7 +393,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 166: value = buf.readShortLE(); position.set( - Position.PREFIX_TEMP + (j + 2 + 8 - 163), + Position.PREFIX_TEMP + (j + 1 + 8 - 163), (value != (short) 0x8000) ? value * 0.05 : null); break; case 167: @@ -402,22 +401,22 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 169: case 170: value = buf.readUnsignedByte(); - position.set("humidity" + (j + 2 - 167), (value != 0xFF) ? value * 0.5 : null); + position.set("humidity" + (j + 1 - 167), (value != 0xFF) ? value * 0.5 : null); break; case 206: position.set("diagnostic", buf.readUnsignedIntLE()); break; default: - if ((207 <= bitNum) && (bitNum <= 222)) { - position.set("user1Byte" + (j + 2 - 207), buf.readUnsignedByte()); - } else if ((223 <= bitNum) && (bitNum <= 237)) { - position.set("user2Byte" + (j + 2 - 223), buf.readUnsignedShortLE()); - } else if ((238 <= bitNum) && (bitNum <= 252)) { - position.set("user4Byte" + (j + 2 - 238), buf.readUnsignedIntLE()); - } else if ((253 <= bitNum) && (bitNum <= 255)) { - position.set("user8Byte" + (j + 2 - 253), buf.readLongLE()); + if ((207 <= j) && (j <= 222)) { + position.set("user1Byte" + (j + 1 - 207), buf.readUnsignedByte()); + } else if ((223 <= j) && (j <= 237)) { + position.set("user2Byte" + (j + 1 - 223), buf.readUnsignedShortLE()); + } else if ((238 <= j) && (j <= 252)) { + position.set("user4Byte" + (j + 1 - 238), buf.readUnsignedIntLE()); + } else if ((253 <= j) && (j <= 255)) { + position.set("user8Byte" + (j + 1 - 253), buf.readLongLE()); } else { - buf.skipBytes(getItemLength(bitNum)); + buf.skipBytes(getItemLength(j)); } break; } -- cgit v1.2.3 From 190f74fedf00303abdbc7228b5bb389533da3f5a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 29 Sep 2023 15:38:31 +0900 Subject: GlobalStar Smart One C support --- .../protocol/GlobalstarProtocolDecoder.java | 56 +++++++++++++++++----- .../protocol/GlobalstarProtocolDecoderTest.java | 4 ++ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index 0ddb95c14..b75e612b8 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -27,6 +27,7 @@ import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.config.Keys; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -64,6 +65,12 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { private final XPath xPath; private final XPathExpression messageExpression; + private boolean alternative; + + public void setAlternative(boolean alternative) { + this.alternative = alternative; + } + public GlobalstarProtocolDecoder(Protocol protocol) { super(protocol); try { @@ -82,6 +89,11 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { } } + @Override + protected void init() { + this.alternative = getConfig().getBoolean(Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName())); + } + private void sendResponse(Channel channel, String messageId) throws TransformerException { Document document = documentBuilder.newDocument(); @@ -135,32 +147,50 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); position.setTime(new Date(Long.parseLong(xPath.evaluate("unixTime", node)) * 1000)); ByteBuf buf = Unpooled.wrappedBuffer( DataConverter.parseHex(xPath.evaluate("payload", node).substring(2))); int flags = buf.readUnsignedByte(); - position.set(Position.PREFIX_IN + 1, !BitUtil.check(flags, 1)); - position.set(Position.PREFIX_IN + 2, !BitUtil.check(flags, 2)); - position.set(Position.KEY_CHARGE, !BitUtil.check(flags, 3)); - if (BitUtil.check(flags, 4)) { - position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + int type; + if (alternative) { + type = BitUtil.to(flags, 1); + position.setValid(true); + position.set(Position.PREFIX_IN + 1, !BitUtil.check(flags, 1)); + position.set(Position.PREFIX_IN + 2, !BitUtil.check(flags, 2)); + position.set(Position.KEY_CHARGE, !BitUtil.check(flags, 3)); + if (BitUtil.check(flags, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + } + position.setCourse(BitUtil.from(flags, 5) * 45); + } else { + type = BitUtil.to(flags, 2); + if (BitUtil.check(flags, 2)) { + position.set("batteryReplace", true); + } + position.setValid(!BitUtil.check(flags, 3)); } - position.setCourse(BitUtil.from(flags, 5) * 45); - double latitude = buf.readUnsignedMedium() * 90.0 / (1 << 23); position.setLatitude(latitude > 90 ? latitude - 180 : latitude); double longitude = buf.readUnsignedMedium() * 180.0 / (1 << 23); position.setLongitude(longitude > 180 ? longitude - 360 : longitude); - int speed = buf.readUnsignedByte(); - position.setSpeed(UnitsConverter.knotsFromKph(speed)); - - position.set("batteryReplace", BitUtil.check(buf.readUnsignedByte(), 7)); + int speed = 0; + if (alternative) { + speed = buf.readUnsignedByte(); + position.setSpeed(UnitsConverter.knotsFromKph(speed)); + position.set("batteryReplace", BitUtil.check(buf.readUnsignedByte(), 7)); + } else if (type == 0) { + position.set(Position.KEY_INPUT, BitUtil.to(buf.readUnsignedByte(), 4)); + int other = buf.readUnsignedByte(); + if (BitUtil.check(other, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + } + position.set(Position.KEY_MOTION, BitUtil.check(other, 6)); + } if (speed != 0xff) { positions.add(position); diff --git a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java index 8d4210e9d..995fffad0 100644 --- a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java @@ -11,6 +11,8 @@ public class GlobalstarProtocolDecoderTest extends ProtocolTest { var decoder = inject(new GlobalstarProtocolDecoder(null)); + decoder.setAlternative(true); + verifyNull(decoder, request(HttpMethod.POST, "/", buffer( "\n", "\n", @@ -22,6 +24,8 @@ public class GlobalstarProtocolDecoderTest extends ProtocolTest { "\n", ""))); + decoder.setAlternative(false); + verifyPositions(decoder, request(HttpMethod.POST, "/", buffer( "", "", -- cgit v1.2.3 From 8edfd96b0e14df98b817ed1b4f8edab77562d632 Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Fri, 29 Sep 2023 22:27:21 +0300 Subject: minor fixes: - field 54 rename; - field 53, 66 corrections. --- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 2dca220ed..0d085c871 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -315,13 +315,13 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 15)) { position.set("obdFuelLevel", BitUtil.to(value, 14)); } else { - position.set("obdFuel", BitUtil.to(value, 14) / 10.0); + position.set("obdFuel", BitUtil.to(value, 14) * 0.1); } } break; case 54: double dValue = buf.readFloatLE() * 0.5; - position.set(Position.KEY_FUEL_USED, (dValue >= 0) ? dValue : null); + position.set("fuelUsed", (dValue >= 0) ? dValue : null); break; case 55: value = buf.readUnsignedShortLE(); @@ -360,7 +360,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 15)) { position.set("obdAdBlueLevel", BitUtil.to(value, 14)); } else { - position.set("obdAdBlue", BitUtil.to(value, 14) / 10.0); + position.set("obdAdBlue", BitUtil.to(value, 14) * 0.1); } } break; -- cgit v1.2.3 From db169dab28ac661adc3eb10e3f395c5b2296d9cc Mon Sep 17 00:00:00 2001 From: Yuriy Piskarev Date: Fri, 29 Sep 2023 23:03:20 +0300 Subject: field 54: restore key, rename variable --- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 0d085c871..ffcaa0c6c 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -320,8 +320,8 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { } break; case 54: - double dValue = buf.readFloatLE() * 0.5; - position.set("fuelUsed", (dValue >= 0) ? dValue : null); + double fuelUsed = buf.readFloatLE() * 0.5; + position.set(Position.KEY_FUEL_USED, (fuelUsed >= 0) ? fuelUsed : null); break; case 55: value = buf.readUnsignedShortLE(); -- cgit v1.2.3 From 65f54c200cf0dcadaa9a1ce685e3eaeb88ce7506 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 1 Oct 2023 05:39:45 +0900 Subject: Support FMT100 EYE beacon --- .../traccar/protocol/TeltonikaProtocolDecoder.java | 28 ++++++++++++++++++++++ .../protocol/TeltonikaProtocolDecoderTest.java | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index e888642b4..16c1dd210 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -588,6 +588,34 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } index += 1; } + } else if (id == 10829 || id == 10831) { + ByteBuf data = buf.readSlice(length); + data.readUnsignedByte(); // header + for (int i = 1; data.isReadable(); i++) { + ByteBuf beacon = data.readSlice(data.readUnsignedByte()); + while (beacon.isReadable()) { + int parameterId = beacon.readUnsignedByte(); + int parameterLength = beacon.readUnsignedByte(); + switch (parameterId) { + case 0: + position.set("tag" + i + "Rssi", (int) beacon.readByte()); + break; + case 1: + String beaconId = ByteBufUtil.hexDump(beacon.readSlice(parameterLength)); + position.set("tag" + i + "Id", beaconId); + break; + case 13: + position.set("tag" + i + "LowBattery", beacon.readUnsignedByte()); + break; + case 14: + position.set("tag" + i + "Battery", beacon.readUnsignedShort()); + break; + default: + beacon.skipBytes(parameterLength); + break; + } + } + } } else { position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length))); } diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java index 0b4f1d243..7a6bdba54 100644 --- a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -15,6 +15,10 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "000F313233343536373839303132333435")); + verifyAttribute(decoder, binary( + "000000000000004b8e010000018368952793000f0e54fc209ab05800b300b40e00002a4f0001000000000000000000012a4f001e011c0001a40110eb47706aa38255aa96f21a154e2d00550d01000e020bd6010000823f"), + "tag1Battery", 3030); + verifyAttribute(decoder, binary( "00000000000000240d01060000001c642b3ad14754534c7c367c317c307c31323734393838347c317c0d0a010000ec11"), Position.KEY_DRIVER_UNIQUE_ID, "12749884"); -- cgit v1.2.3 From 0ad9b4c84b5eb4b9b58f8ca45adff99526ae193e Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Sun, 1 Oct 2023 00:06:27 +0200 Subject: Ruptela: Support Heartbeat message type --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 649de7c5c..b381b93f8 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -51,6 +51,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_SMS_VIA_GPRS = 8; public static final int MSG_DTCS = 9; public static final int MSG_IDENTIFICATION = 15; + public static final int MSG_HEARTBEAT = 16; public static final int MSG_SET_IO = 17; public static final int MSG_FILES = 37; public static final int MSG_EXTENDED_RECORDS = 68; @@ -388,7 +389,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { return null; - } else if (type == MSG_IDENTIFICATION) { + } else if (type == MSG_IDENTIFICATION || type == MSG_HEARTBEAT) { ByteBuf content = Unpooled.buffer(); content.writeByte(1); -- cgit v1.2.3 From 60e9026a968fb639a617670d8b03e052381d5c55 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Sun, 1 Oct 2023 00:12:02 +0200 Subject: Ruptela: Fix a bug with extended records spanning multiple messages --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index b381b93f8..d4f9808ae 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -243,7 +243,11 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { int currentRecord = BitUtil.to(recordExtension, 4); if (currentRecord > 0 && currentRecord <= mergeRecordCount) { - position = positions.remove(positions.size() - 1); + if (positions.size() == 0) { + getLastLocation(position, null); + } else { + position = positions.remove(positions.size() - 1); + } } } -- cgit v1.2.3 From 630a32e817526735a77b4aa375a3ac39bcf780d8 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Sun, 1 Oct 2023 01:03:06 +0200 Subject: Ruptela: Anwser with a negative ack on exceptions - this creates a retry delay so that the device does not burn thorough the data. --- .../traccar/protocol/RuptelaProtocolDecoder.java | 157 +++++++++++---------- 1 file changed, 84 insertions(+), 73 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index d4f9808ae..720926db2 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -227,92 +227,103 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { List positions = new LinkedList<>(); - buf.readUnsignedByte(); // records left - int count = buf.readUnsignedByte(); + try { + buf.readUnsignedByte(); // records left + int count = buf.readUnsignedByte(); - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); + for (int i = 0; i < count; i++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - buf.readUnsignedByte(); // timestamp extension - - if (type == MSG_EXTENDED_RECORDS) { - int recordExtension = buf.readUnsignedByte(); - int mergeRecordCount = BitUtil.from(recordExtension, 4); - int currentRecord = BitUtil.to(recordExtension, 4); - - if (currentRecord > 0 && currentRecord <= mergeRecordCount) { - if (positions.size() == 0) { - getLastLocation(position, null); - } else { - position = positions.remove(positions.size() - 1); + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + buf.readUnsignedByte(); // timestamp extension + + if (type == MSG_EXTENDED_RECORDS) { + int recordExtension = buf.readUnsignedByte(); + int mergeRecordCount = BitUtil.from(recordExtension, 4); + int currentRecord = BitUtil.to(recordExtension, 4); + + if (currentRecord > 0 && currentRecord <= mergeRecordCount) { + if (positions.size() == 0) { + getLastLocation(position, null); + } else { + position = positions.remove(positions.size() - 1); + } } } - } - buf.readUnsignedByte(); // priority (reserved) - - int longitude = buf.readInt(); - int latitude = buf.readInt(); - if (longitude > Integer.MIN_VALUE && latitude > Integer.MIN_VALUE) { - position.setValid(true); - position.setLongitude(longitude / 10000000.0); - position.setLatitude(latitude / 10000000.0); - position.setAltitude(buf.readUnsignedShort() / 10.0); - position.setCourse(buf.readUnsignedShort() / 100.0); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); - } else { - buf.skipBytes(8); - getLastLocation(position, null); - } + buf.readUnsignedByte(); // priority (reserved) + + int longitude = buf.readInt(); + int latitude = buf.readInt(); + if (longitude > Integer.MIN_VALUE && latitude > Integer.MIN_VALUE) { + position.setValid(true); + position.setLongitude(longitude / 10000000.0); + position.setLatitude(latitude / 10000000.0); + position.setAltitude(buf.readUnsignedShort() / 10.0); + position.setCourse(buf.readUnsignedShort() / 100.0); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); + } else { + buf.skipBytes(8); + getLastLocation(position, null); + } - if (type == MSG_EXTENDED_RECORDS) { - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - } else { - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - } + if (type == MSG_EXTENDED_RECORDS) { + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + } else { + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + } - // Read 1 byte data - int valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 1); - } + // Read 1 byte data + int valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 1); + } - // Read 2 byte data - valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 2); - } + // Read 2 byte data + valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 2); + } - // Read 4 byte data - valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 4); - } + // Read 4 byte data + valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 4); + } - // Read 8 byte data - valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 8); - } + // Read 8 byte data + valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 8); + } - decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); // can driver - decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); // tco driver + decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); // can driver + decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); // tco driver - Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); - Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); - if (tagIdPart1 != null && tagIdPart2 != null) { - position.set("tagId", Long.toHexString(tagIdPart1) + Long.toHexString(tagIdPart2)); - } + Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); + Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); + if (tagIdPart1 != null && tagIdPart2 != null) { + position.set("tagId", Long.toHexString(tagIdPart1) + Long.toHexString(tagIdPart2)); + } - positions.add(position); + positions.add(position); + } + } catch (Exception e) { + ByteBuf content = Unpooled.buffer(); + content.writeByte(0); + ByteBuf response = RuptelaProtocolEncoder.encodeContent(0, content); + content.release(); + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + throw e; } if (channel != null) { -- cgit v1.2.3 From 45a0d3b8673a5bab98570b84a864e6b313fe2899 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 3 Oct 2023 07:24:27 +0800 Subject: Add Seeworld temp and humidity --- .../java/org/traccar/protocol/Gt06ProtocolDecoder.java | 17 +++++++++++++++++ .../org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 161d04d8d..e9bdaf194 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -124,6 +124,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { WETRUST, JC400, SL4X, + SEEWORLD, } private Variant variant; @@ -901,6 +902,20 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } } + if (type == MSG_GPS_LBS_2 && variant == Variant.SEEWORLD) { + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + buf.readUnsignedByte(); // reporting mode + buf.readUnsignedByte(); // supplementary transmission + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + buf.readUnsignedInt(); // travel time + int temperature = buf.readUnsignedShort(); + if (BitUtil.check(temperature, 15)) { + temperature = -BitUtil.to(temperature, 15); + } + position.set(Position.PREFIX_TEMP + 1, temperature * 0.01); + position.set("humidity", buf.readUnsignedShort() * 0.01); + } + if ((type == MSG_GPS_LBS_2 || type == MSG_GPS_LBS_3 || type == MSG_GPS_LBS_4) && buf.readableBytes() >= 3 + 6) { position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); @@ -1468,6 +1483,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.JC400; } else if (header == 0x7878 && type == MSG_LBS_3 && length == 0x37) { variant = Variant.SL4X; + } else if (header == 0x7878 && type == MSG_GPS_LBS_2 && length == 0x2f) { + variant = Variant.SEEWORLD; } else { variant = Variant.STANDARD; } diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 9b196e501..a2ee4d1bc 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78782f22170a020b2737cf02c568a8089fc0dc125c4d01369a371b0a6967020000000007327a00000000001500260074544c0d0a"), + "humidity", 53.76); + verifyAttribute(decoder, binary( "78785995ffff01170719152013df0163d45f041ee52018be002f00876900004556454e545f3836323739383035303137353131325f30303030303030305f323032335f30375f32355f31385f33325f30355f31342e6d70340119d15a0d0a"), Position.KEY_EVENT, 0x69); -- cgit v1.2.3 From a10728fc9174591c4535b5ced290f7b51ec98851 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Oct 2023 07:59:51 +0800 Subject: Return queued command with id --- .../java/org/traccar/api/resource/CommandResource.java | 18 ++++++++++++++---- .../java/org/traccar/database/CommandsManager.java | 9 +++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index d50c7ee0c..c23d91e77 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -117,20 +117,30 @@ public class CommandResource extends ExtendedObjectResource { } else { permissionsService.checkRestriction(getUserId(), UserRestrictions::getLimitCommands); } - boolean result = true; + if (groupId > 0) { permissionsService.checkPermission(Group.class, getUserId(), groupId); var devices = DeviceUtil.getAccessibleDevices(storage, getUserId(), List.of(), List.of(groupId)); + List queuedCommands = new ArrayList<>(); for (Device device : devices) { Command command = QueuedCommand.fromCommand(entity).toCommand(); command.setDeviceId(device.getId()); - result = commandsManager.sendCommand(command) && result; + QueuedCommand queuedCommand = commandsManager.sendCommand(command); + if (queuedCommand != null) { + queuedCommands.add(queuedCommand); + } + } + if (!queuedCommands.isEmpty()) { + return Response.accepted(queuedCommands).build(); } } else { permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); - result = commandsManager.sendCommand(entity); + QueuedCommand queuedCommand = commandsManager.sendCommand(entity); + if (queuedCommand != null) { + return Response.accepted(queuedCommand).build(); + } } - return result ? Response.ok(entity).build() : Response.accepted(entity).build(); + return Response.ok(entity).build(); } @GET diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index fb8f2f9d6..bef696e58 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -61,7 +61,7 @@ public class CommandsManager implements BroadcastInterface { broadcastService.registerListener(this); } - public boolean sendCommand(Command command) throws Exception { + public QueuedCommand sendCommand(Command command) throws Exception { long deviceId = command.getDeviceId(); if (command.getTextChannel()) { if (smsManager == null) { @@ -84,12 +84,13 @@ public class CommandsManager implements BroadcastInterface { if (deviceSession != null && deviceSession.supportsLiveCommands()) { deviceSession.sendCommand(command); } else { - storage.addObject(QueuedCommand.fromCommand(command), new Request(new Columns.Exclude("id"))); + QueuedCommand queuedCommand = QueuedCommand.fromCommand(command); + queuedCommand.setId(storage.addObject(queuedCommand, new Request(new Columns.Exclude("id")))); broadcastService.updateCommand(true, deviceId); - return false; + return queuedCommand; } } - return true; + return null; } public Collection readQueuedCommands(long deviceId) { -- cgit v1.2.3 From 6c78fc675501ab348f877e423b984d1a2a132ef1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Oct 2023 08:16:10 +0800 Subject: Event for sent queued commands --- src/main/java/org/traccar/database/CommandsManager.java | 14 +++++++++++++- src/main/java/org/traccar/model/Event.java | 1 + templates/full/queuedCommandSent.vm | 11 +++++++++++ templates/short/queuedCommandSent.vm | 2 ++ 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 templates/full/queuedCommandSent.vm create mode 100644 templates/short/queuedCommandSent.vm diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index bef696e58..90180b989 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -22,6 +22,7 @@ import org.traccar.broadcast.BroadcastInterface; import org.traccar.broadcast.BroadcastService; import org.traccar.model.Command; import org.traccar.model.Device; +import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.QueuedCommand; import org.traccar.session.ConnectionManager; @@ -38,6 +39,8 @@ import jakarta.annotation.Nullable; import jakarta.inject.Inject; import jakarta.inject.Singleton; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Collectors; @Singleton @@ -48,16 +51,19 @@ public class CommandsManager implements BroadcastInterface { private final SmsManager smsManager; private final ConnectionManager connectionManager; private final BroadcastService broadcastService; + private final NotificationManager notificationManager; @Inject public CommandsManager( Storage storage, ServerManager serverManager, @Nullable SmsManager smsManager, - ConnectionManager connectionManager, BroadcastService broadcastService) { + ConnectionManager connectionManager, BroadcastService broadcastService, + NotificationManager notificationManager) { this.storage = storage; this.serverManager = serverManager; this.smsManager = smsManager; this.connectionManager = connectionManager; this.broadcastService = broadcastService; + this.notificationManager = notificationManager; broadcastService.registerListener(this); } @@ -103,10 +109,16 @@ public class CommandsManager implements BroadcastInterface { new Columns.All(), new Condition.Equals("deviceId", deviceId), new Order("id", false, count))); + Map events = new HashMap<>(); for (var command : commands) { storage.removeObject(QueuedCommand.class, new Request( new Condition.Equals("id", command.getId()))); + + Event event = new Event(Event.TYPE_QUEUED_COMMAND_SENT, command.getDeviceId()); + event.set("id", command.getId()); + events.put(event, null); } + notificationManager.updateEvents(events); return commands.stream().map(QueuedCommand::toCommand).collect(Collectors.toList()); } catch (StorageException e) { throw new RuntimeException(e); diff --git a/src/main/java/org/traccar/model/Event.java b/src/main/java/org/traccar/model/Event.java index 0e851d748..6f90de9da 100644 --- a/src/main/java/org/traccar/model/Event.java +++ b/src/main/java/org/traccar/model/Event.java @@ -46,6 +46,7 @@ public class Event extends Message { public static final String TYPE_DEVICE_UNKNOWN = "deviceUnknown"; public static final String TYPE_DEVICE_OFFLINE = "deviceOffline"; public static final String TYPE_DEVICE_INACTIVE = "deviceInactive"; + public static final String TYPE_QUEUED_COMMAND_SENT = "queuedCommandSent"; public static final String TYPE_DEVICE_MOVING = "deviceMoving"; public static final String TYPE_DEVICE_STOPPED = "deviceStopped"; diff --git a/templates/full/queuedCommandSent.vm b/templates/full/queuedCommandSent.vm new file mode 100644 index 000000000..148dd2094 --- /dev/null +++ b/templates/full/queuedCommandSent.vm @@ -0,0 +1,11 @@ +#set($subject = "$device.name: queued command sent") + + + +Device: $device.name
+Queued command sent
+Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
+
+Unsubscribe + + diff --git a/templates/short/queuedCommandSent.vm b/templates/short/queuedCommandSent.vm new file mode 100644 index 000000000..67f031280 --- /dev/null +++ b/templates/short/queuedCommandSent.vm @@ -0,0 +1,2 @@ +#set($subject = "$device.name: queued command sent") +Queued command sent to $device.name at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone) -- cgit v1.2.3 From 0867ac8efb8c4b033a9d22ce311ffcf301971b24 Mon Sep 17 00:00:00 2001 From: Matjaž Črnko Date: Wed, 4 Oct 2023 15:37:34 +0200 Subject: Ruptela: remove exception handling. --- .../traccar/protocol/RuptelaProtocolDecoder.java | 157 ++++++++++----------- 1 file changed, 73 insertions(+), 84 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 720926db2..d4f9808ae 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -227,103 +227,92 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { List positions = new LinkedList<>(); - try { - buf.readUnsignedByte(); // records left - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - buf.readUnsignedByte(); // timestamp extension + buf.readUnsignedByte(); // records left + int count = buf.readUnsignedByte(); - if (type == MSG_EXTENDED_RECORDS) { - int recordExtension = buf.readUnsignedByte(); - int mergeRecordCount = BitUtil.from(recordExtension, 4); - int currentRecord = BitUtil.to(recordExtension, 4); + for (int i = 0; i < count; i++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); - if (currentRecord > 0 && currentRecord <= mergeRecordCount) { - if (positions.size() == 0) { - getLastLocation(position, null); - } else { - position = positions.remove(positions.size() - 1); - } + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + buf.readUnsignedByte(); // timestamp extension + + if (type == MSG_EXTENDED_RECORDS) { + int recordExtension = buf.readUnsignedByte(); + int mergeRecordCount = BitUtil.from(recordExtension, 4); + int currentRecord = BitUtil.to(recordExtension, 4); + + if (currentRecord > 0 && currentRecord <= mergeRecordCount) { + if (positions.size() == 0) { + getLastLocation(position, null); + } else { + position = positions.remove(positions.size() - 1); } } + } - buf.readUnsignedByte(); // priority (reserved) - - int longitude = buf.readInt(); - int latitude = buf.readInt(); - if (longitude > Integer.MIN_VALUE && latitude > Integer.MIN_VALUE) { - position.setValid(true); - position.setLongitude(longitude / 10000000.0); - position.setLatitude(latitude / 10000000.0); - position.setAltitude(buf.readUnsignedShort() / 10.0); - position.setCourse(buf.readUnsignedShort() / 100.0); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); - } else { - buf.skipBytes(8); - getLastLocation(position, null); - } - - if (type == MSG_EXTENDED_RECORDS) { - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - } else { - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - } + buf.readUnsignedByte(); // priority (reserved) + + int longitude = buf.readInt(); + int latitude = buf.readInt(); + if (longitude > Integer.MIN_VALUE && latitude > Integer.MIN_VALUE) { + position.setValid(true); + position.setLongitude(longitude / 10000000.0); + position.setLatitude(latitude / 10000000.0); + position.setAltitude(buf.readUnsignedShort() / 10.0); + position.setCourse(buf.readUnsignedShort() / 100.0); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); + } else { + buf.skipBytes(8); + getLastLocation(position, null); + } - // Read 1 byte data - int valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 1); - } + if (type == MSG_EXTENDED_RECORDS) { + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + } else { + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + } - // Read 2 byte data - valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 2); - } + // Read 1 byte data + int valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 1); + } - // Read 4 byte data - valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 4); - } + // Read 2 byte data + valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 2); + } - // Read 8 byte data - valueCount = buf.readUnsignedByte(); - for (int j = 0; j < valueCount; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 8); - } + // Read 4 byte data + valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 4); + } - decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); // can driver - decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); // tco driver + // Read 8 byte data + valueCount = buf.readUnsignedByte(); + for (int j = 0; j < valueCount; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 8); + } - Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); - Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); - if (tagIdPart1 != null && tagIdPart2 != null) { - position.set("tagId", Long.toHexString(tagIdPart1) + Long.toHexString(tagIdPart2)); - } + decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); // can driver + decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); // tco driver - positions.add(position); + Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); + Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); + if (tagIdPart1 != null && tagIdPart2 != null) { + position.set("tagId", Long.toHexString(tagIdPart1) + Long.toHexString(tagIdPart2)); } - } catch (Exception e) { - ByteBuf content = Unpooled.buffer(); - content.writeByte(0); - ByteBuf response = RuptelaProtocolEncoder.encodeContent(0, content); - content.release(); - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - throw e; + + positions.add(position); } if (channel != null) { -- cgit v1.2.3 From fa2a61f6487c9ad8a338cdacf18f15be9c299cfd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 5 Oct 2023 16:10:18 +0800 Subject: Fix Seeworld cell decoding --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 4 +++- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index e9bdaf194..f676e7363 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -358,7 +358,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { long cid; if (type == MSG_LBS_ALARM || type == MSG_GPS_LBS_7) { cid = buf.readLong(); - } else if (type == MSG_GPS_LBS_6) { + } else if (type == MSG_GPS_LBS_6 || variant == Variant.SEEWORLD) { cid = buf.readUnsignedInt(); } else { cid = buf.readUnsignedMedium(); @@ -1485,6 +1485,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.SL4X; } else if (header == 0x7878 && type == MSG_GPS_LBS_2 && length == 0x2f) { variant = Variant.SEEWORLD; + } else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_1 && length == 0x26) { + variant = Variant.SEEWORLD; } else { variant = Variant.STANDARD; } diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index a2ee4d1bc..d573957b3 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -18,8 +18,8 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { "78780D01086471700328358100093F040D0A")); verifyAttribute(decoder, binary( - "78782f22170a020b2737cf02c568a8089fc0dc125c4d01369a371b0a6967020000000007327a00000000001500260074544c0d0a"), - "humidity", 53.76); + "78782f221709130f3a32cc02c55f2a089f9afc005c2101360481fe066d9b03000000000025d4000000000020002d036049d70d0a"), + Position.PREFIX_TEMP + 1, 0.32); verifyAttribute(decoder, binary( "78785995ffff01170719152013df0163d45f041ee52018be002f00876900004556454e545f3836323739383035303137353131325f30303030303030305f323032335f30375f32355f31385f33325f30355f31342e6d70340119d15a0d0a"), -- cgit v1.2.3 From 91cfe0412753cadb47a0b892864469a2baf4fe31 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 5 Oct 2023 16:12:31 +0800 Subject: Add another test case --- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index d573957b3..8e60fb342 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "787826161709130f3a2dcc02c55f2a089f9af9005c210901360481fe066d9b03413e420102035f92fe0d0a"), + Position.KEY_ALARM, Position.ALARM_SOS); + verifyAttribute(decoder, binary( "78782f221709130f3a32cc02c55f2a089f9afc005c2101360481fe066d9b03000000000025d4000000000020002d036049d70d0a"), Position.PREFIX_TEMP + 1, 0.32); -- cgit v1.2.3 From e3a309155a39d97bffe0e781a66070ef9e38a52f Mon Sep 17 00:00:00 2001 From: Abdelrahman Mousa <109462679+sherbinator@users.noreply.github.com> Date: Thu, 5 Oct 2023 22:07:48 +0200 Subject: (Bugfix-T800X Protocol) Fix messages response for 0x2323 --- .../java/org/traccar/protocol/T800xProtocolDecoder.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index a1093fc32..3353bc57d 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -163,7 +163,12 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { boolean positionType = type == MSG_GPS || type == MSG_GPS_2 || type == MSG_ALARM || type == MSG_ALARM_2; if (!positionType) { - sendResponse(channel, header, type, index, imei, 0); + + if (header == 0x2323) { + sendResponse(channel, header, type, 0x0001, imei, 0); + } else { + sendResponse(channel, header, type, index, imei, 0); + } } if (positionType) { @@ -518,7 +523,12 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { boolean acknowledgement = AttributeUtil.lookup( getCacheManager(), Keys.PROTOCOL_ACK.withPrefix(getProtocolName()), deviceSession.getDeviceId()); if (acknowledgement || type == MSG_ALARM || type == MSG_ALARM_2) { - sendResponse(channel, header, type, index, imei, alarm); + + if (header == 0x2323) { + sendResponse(channel, header, type, 0x0001, imei, alarm); + } else { + sendResponse(channel, header, type, index, imei, alarm); + } } return position; -- cgit v1.2.3 From 47897420cd24c99a74d8b9d84cc289a3f260d3df Mon Sep 17 00:00:00 2001 From: Abdelrahman Mousa <109462679+sherbinator@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:12:44 +0200 Subject: (Refactor-T800X Protocol) messages response for 0x2323 --- .../java/org/traccar/protocol/T800xProtocolDecoder.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index 3353bc57d..ac1108a64 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -163,12 +163,8 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { boolean positionType = type == MSG_GPS || type == MSG_GPS_2 || type == MSG_ALARM || type == MSG_ALARM_2; if (!positionType) { - - if (header == 0x2323) { - sendResponse(channel, header, type, 0x0001, imei, 0); - } else { - sendResponse(channel, header, type, index, imei, 0); - } + var serial = header == 0x2323 ? 0x0001 : index; + sendResponse(channel, header, type, serial, imei, 0); } if (positionType) { @@ -523,12 +519,8 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { boolean acknowledgement = AttributeUtil.lookup( getCacheManager(), Keys.PROTOCOL_ACK.withPrefix(getProtocolName()), deviceSession.getDeviceId()); if (acknowledgement || type == MSG_ALARM || type == MSG_ALARM_2) { - - if (header == 0x2323) { - sendResponse(channel, header, type, 0x0001, imei, alarm); - } else { - sendResponse(channel, header, type, index, imei, alarm); - } + var serial = header == 0x2323 ? 0x0001 : index; + sendResponse(channel, header, type, serial, imei, alarm); } return position; -- cgit v1.2.3 From b8b84db2104b26dfeedbe1faaa4a52fef608cd1c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 7 Oct 2023 06:40:21 +0800 Subject: Inline expression --- src/main/java/org/traccar/protocol/T800xProtocolDecoder.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index ac1108a64..23750be8d 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -163,8 +163,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { boolean positionType = type == MSG_GPS || type == MSG_GPS_2 || type == MSG_ALARM || type == MSG_ALARM_2; if (!positionType) { - var serial = header == 0x2323 ? 0x0001 : index; - sendResponse(channel, header, type, serial, imei, 0); + sendResponse(channel, header, type, header == 0x2323 ? 1 : index, imei, 0); } if (positionType) { @@ -519,8 +518,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { boolean acknowledgement = AttributeUtil.lookup( getCacheManager(), Keys.PROTOCOL_ACK.withPrefix(getProtocolName()), deviceSession.getDeviceId()); if (acknowledgement || type == MSG_ALARM || type == MSG_ALARM_2) { - var serial = header == 0x2323 ? 0x0001 : index; - sendResponse(channel, header, type, serial, imei, alarm); + sendResponse(channel, header, type, header == 0x2323 ? 1 : index, imei, alarm); } return position; -- cgit v1.2.3 From b9c2d03f189abb7360801952ba69138fdf9fe432 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 14 Oct 2023 17:00:41 -0700 Subject: Support Teltonika advanced beacon --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 6 +++++- .../java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 16c1dd210..45afbd0f7 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -588,7 +588,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } index += 1; } - } else if (id == 10829 || id == 10831) { + } else if (id == 548 || id == 10829 || id == 10831) { ByteBuf data = buf.readSlice(length); data.readUnsignedByte(); // header for (int i = 1; data.isReadable(); i++) { @@ -604,6 +604,10 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { String beaconId = ByteBufUtil.hexDump(beacon.readSlice(parameterLength)); position.set("tag" + i + "Id", beaconId); break; + case 2: + String beaconData = ByteBufUtil.hexDump(beacon.readSlice(parameterLength)); + position.set("tag" + i + "Data", beaconData); + break; case 13: position.set("tag" + i + "LowBattery", beacon.readUnsignedByte()); break; diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java index 7a6bdba54..2a8ff87b6 100644 --- a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -15,6 +15,9 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "000F313233343536373839303132333435")); + verifyPositions(decoder, binary( + "00000000000000728e010000018b23dd796300fbf7263c24f9e11a0000000000000002240001000000000000000000010224004501210001e50110cde39f7e42bb55aa788e4a29ed650055020ab70a8f264c6000ffff6b210001b00110f89b907e42bb55aaa3463b29ed650055020ab708bb2600ae0500096c01000051d4")); + verifyAttribute(decoder, binary( "000000000000004b8e010000018368952793000f0e54fc209ab05800b300b40e00002a4f0001000000000000000000012a4f001e011c0001a40110eb47706aa38255aa96f21a154e2d00550d01000e020bd6010000823f"), "tag1Battery", 3030); -- cgit v1.2.3 From 170d3a90376805fbb84df7e16af9229899d413a6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 14 Oct 2023 17:09:55 -0700 Subject: Support topin message type --- src/main/java/org/traccar/protocol/TopinProtocolDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java index b5dd3c4b9..c7b816818 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java @@ -53,6 +53,7 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_WIFI_OFFLINE = 0x17; public static final int MSG_LBS_WIFI = 0x18; public static final int MSG_LBS_WIFI_OFFLINE = 0x19; + public static final int MSG_LBS_WIFI_2 = 0x1A; public static final int MSG_TIME_UPDATE = 0x30; public static final int MSG_SOS_NUMBER = 0x41; public static final int MSG_WIFI = 0x69; @@ -221,7 +222,7 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { return position; } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE - || type == MSG_LBS_WIFI || type == MSG_LBS_WIFI_OFFLINE) { + || type == MSG_LBS_WIFI || type == MSG_LBS_WIFI_2 || type == MSG_LBS_WIFI_OFFLINE) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); -- cgit v1.2.3 From 43e7373576c2137af86febad8d55f948838a900a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 14 Oct 2023 18:36:41 -0700 Subject: Last position computed attributes --- src/main/java/org/traccar/config/Keys.java | 9 +++++++- .../traccar/handler/ComputedAttributesHandler.java | 24 +++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 23a983e7b..15bfec09d 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1482,12 +1482,19 @@ public final class Keys { List.of(KeyType.CONFIG, KeyType.DEVICE)); /** - * Enable computed attributes processing. + * Include device attributes in the computed attribute context. */ public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey( "processing.computedAttributes.deviceAttributes", List.of(KeyType.CONFIG)); + /** + * Include last position attributes in the computed attribute context. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_LAST_ATTRIBUTES = new BooleanConfigKey( + "processing.computedAttributes.lastAttributes", + List.of(KeyType.CONFIG)); + /** * Enable local variables declaration. */ diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 042747359..3f8a8c0bd 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -59,6 +59,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { private final JexlFeatures features; private final boolean includeDeviceAttributes; + private final boolean includeLastAttributes; @Inject public ComputedAttributesHandler(Config config, CacheManager cacheManager) { @@ -81,6 +82,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { .sandbox(sandbox) .create(); includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); + includeLastAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LAST_ATTRIBUTES); } private MapContext prepareContext(Position position) { @@ -93,6 +95,10 @@ public class ComputedAttributesHandler extends BaseDataHandler { } } } + Position last = null; + if (includeLastAttributes) { + last = cacheManager.getPosition(position.getDeviceId()); + } Set methods = new HashSet<>(Arrays.asList(position.getClass().getMethods())); Arrays.asList(Object.class.getMethods()).forEach(methods::remove); for (Method method : methods) { @@ -102,9 +108,17 @@ public class ComputedAttributesHandler extends BaseDataHandler { try { if (!method.getReturnType().equals(Map.class)) { result.set(name, method.invoke(position)); + if (last != null) { + result.set(prefixAttribute("last", name), method.invoke(last)); + } } else { - for (Object key : ((Map) method.invoke(position)).keySet()) { - result.set((String) key, ((Map) method.invoke(position)).get(key)); + for (Map.Entry entry : ((Map) method.invoke(position)).entrySet()) { + result.set((String) entry.getKey(), entry.getValue()); + } + if (last != null) { + for (Map.Entry entry : ((Map) method.invoke(last)).entrySet()) { + result.set(prefixAttribute("last", (String) entry.getKey()), entry.getValue()); + } } } } catch (IllegalAccessException | InvocationTargetException error) { @@ -112,7 +126,11 @@ public class ComputedAttributesHandler extends BaseDataHandler { } } } - return result; + return result;//Character.toUpperCase(column.charAt(0)) + column.substring(1) + } + + private String prefixAttribute(String prefix, String key) { + return prefix + Character.toUpperCase(key.charAt(0)) + key.substring(1); } /** -- cgit v1.2.3 From 6cf0435a85918b15a74014da20a151f971e9e43b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 14 Oct 2023 18:55:10 -0700 Subject: Remove comment --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 3f8a8c0bd..8b010ceae 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -126,7 +126,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { } } } - return result;//Character.toUpperCase(column.charAt(0)) + column.substring(1) + return result; } private String prefixAttribute(String prefix, String key) { -- cgit v1.2.3 From 33d01cda7bb678bb604404f18c8f4e66a40eaa55 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 16 Oct 2023 07:28:26 -0700 Subject: Negative signal strength value --- src/main/java/org/traccar/model/CellTower.java | 2 +- src/main/java/org/traccar/model/WifiAccessPoint.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/model/CellTower.java b/src/main/java/org/traccar/model/CellTower.java index 355594c64..4277cc4c4 100644 --- a/src/main/java/org/traccar/model/CellTower.java +++ b/src/main/java/org/traccar/model/CellTower.java @@ -104,7 +104,7 @@ public class CellTower { } public void setSignalStrength(Integer signalStrength) { - this.signalStrength = signalStrength; + this.signalStrength = signalStrength > 0 ? -signalStrength : signalStrength; } public void setOperator(long operator) { diff --git a/src/main/java/org/traccar/model/WifiAccessPoint.java b/src/main/java/org/traccar/model/WifiAccessPoint.java index e28c1b935..64858f4c7 100644 --- a/src/main/java/org/traccar/model/WifiAccessPoint.java +++ b/src/main/java/org/traccar/model/WifiAccessPoint.java @@ -52,7 +52,7 @@ public class WifiAccessPoint { } public void setSignalStrength(Integer signalStrength) { - this.signalStrength = signalStrength; + this.signalStrength = signalStrength > 0 ? -signalStrength : signalStrength; } private Integer channel; -- cgit v1.2.3 From d3631eb7286338a0ea046a511aa5cbfce470c7b7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 16 Oct 2023 07:38:12 -0700 Subject: Option to require Wi-Fi geolocation --- src/main/java/org/traccar/config/Keys.java | 9 ++++++++- src/main/java/org/traccar/handler/GeolocationHandler.java | 7 +++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 15bfec09d..91063a8e0 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -1649,6 +1649,13 @@ public final class Keys { "geolocation.reuse", List.of(KeyType.CONFIG)); + /** + * Process geolocation only when Wi-Fi information is available. This makes the result more accurate. + */ + public static final ConfigKey GEOLOCATION_REQUIRE_WIFI = new BooleanConfigKey( + "geolocation.requireWifi", + List.of(KeyType.CONFIG)); + /** * Default MCC value to use if device doesn't report MCC. */ diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java index e7389f22d..a54ea03e3 100644 --- a/src/main/java/org/traccar/handler/GeolocationHandler.java +++ b/src/main/java/org/traccar/handler/GeolocationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -37,6 +37,7 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { private final StatisticsManager statisticsManager; private final boolean processInvalidPositions; private final boolean reuse; + private final boolean requireWifi; public GeolocationHandler( Config config, GeolocationProvider geolocationProvider, CacheManager cacheManager, @@ -46,6 +47,7 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { this.statisticsManager = statisticsManager; processInvalidPositions = config.getBoolean(Keys.GEOLOCATION_PROCESS_INVALID_POSITIONS); reuse = config.getBoolean(Keys.GEOLOCATION_REUSE); + requireWifi = config.getBoolean(Keys.GEOLOCATION_REQUIRE_WIFI); } @Override @@ -53,7 +55,8 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { if (message instanceof Position) { final Position position = (Position) message; if ((position.getOutdated() || processInvalidPositions && !position.getValid()) - && position.getNetwork() != null) { + && position.getNetwork() != null + && (!requireWifi || position.getNetwork().getWifiAccessPoints() != null)) { if (reuse) { Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && position.getNetwork().equals(lastPosition.getNetwork())) { -- cgit v1.2.3 From 37ed394724c0bdcc6f98f421e71d76916206ed30 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 17 Oct 2023 21:02:34 -0700 Subject: Seeworld battery level decoding --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 3 ++- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index f676e7363..cf7cd12d3 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -841,7 +841,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // working mode position.set(Position.KEY_POWER, buf.readUnsignedShort() / 100.0); } else { - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 100 / 6); + int battery = buf.readUnsignedByte(); + position.set(Position.KEY_BATTERY_LEVEL, battery <= 6 ? battery * 100 / 6 : battery); position.set(Position.KEY_RSSI, buf.readUnsignedByte()); short alarmExtension = buf.readUnsignedByte(); if (variant != Variant.VXT01) { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 8e60fb342..be8f4f5ef 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78782616170A080C0E24C0027C58AD0C2B8B0100454E0901CC0025030328E7A0005D4B13021EC373170D0A"), + Position.KEY_BATTERY_LEVEL, 93); + verifyAttribute(decoder, binary( "787826161709130f3a2dcc02c55f2a089f9af9005c210901360481fe066d9b03413e420102035f92fe0d0a"), Position.KEY_ALARM, Position.ALARM_SOS); -- cgit v1.2.3 From a08bc10a8fd15a6b0fa4c04607eeae325e0c5407 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 20 Oct 2023 07:44:06 -0700 Subject: Support Teltonika DSM protocol --- .../org/traccar/protocol/DualcamProtocolDecoder.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index d03f7648d..5a6425e7e 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 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. @@ -42,6 +42,8 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_COMPLETE = 5; public static final int MSG_FILE_REQUEST = 8; public static final int MSG_INIT_REQUEST = 9; + public static final int MSG_PATH_REQUEST = 0x000C; + public static final int MSG_PATH_RESPONSE = 0x000D; private String uniqueId; private int packetCount; @@ -65,7 +67,11 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { long settings = buf.readUnsignedInt(); if (channel != null && deviceSession != null) { ByteBuf response = Unpooled.buffer(); - if (BitUtil.between(settings, 26, 30) > 0) { + if (BitUtil.check(settings, 25)) { + response.writeShort(MSG_PATH_REQUEST); + response.writeShort(2); + response.writeShort(0); + } else if (BitUtil.between(settings, 26, 30) > 0) { response.writeShort(MSG_FILE_REQUEST); String file; if (BitUtil.check(settings, 26)) { @@ -130,6 +136,13 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { currentPacket += 1; } break; + case MSG_PATH_RESPONSE: + String file = buf.readCharSequence(buf.readUnsignedShort(), StandardCharsets.US_ASCII).toString(); + ByteBuf response = Unpooled.buffer(); + response.writeShort(MSG_FILE_REQUEST); + response.writeShort(file.length()); + response.writeCharSequence(file, StandardCharsets.US_ASCII); + break; default: break; } -- cgit v1.2.3 From b7145ea2e9d7efabb0d9806e76e7ac2995e56b27 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 20 Oct 2023 17:35:35 -0700 Subject: Fix DSM response handling --- .../java/org/traccar/protocol/DualcamProtocolDecoder.java | 11 +++++++---- .../java/org/traccar/protocol/DualcamProtocolDecoderTest.java | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index 5a6425e7e..f6712d7f2 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -138,10 +138,13 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { break; case MSG_PATH_RESPONSE: String file = buf.readCharSequence(buf.readUnsignedShort(), StandardCharsets.US_ASCII).toString(); - ByteBuf response = Unpooled.buffer(); - response.writeShort(MSG_FILE_REQUEST); - response.writeShort(file.length()); - response.writeCharSequence(file, StandardCharsets.US_ASCII); + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(MSG_FILE_REQUEST); + response.writeShort(file.length()); + response.writeCharSequence(file, StandardCharsets.US_ASCII); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } break; default: break; diff --git a/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java index de70e2b63..e1c31fc47 100644 --- a/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class DualcamProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "000000050001403a4abaa31444000400")); + verifyNull(decoder, binary( + "000d001e64736d2f706963747572652f3233313032302f3233313435322e6a706700")); + verifyNull(decoder, binary( "00010006000000110000")); -- cgit v1.2.3 From 74ead779cd0b275620ffd399bac7b57f4bc02deb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 25 Oct 2023 20:42:52 -0700 Subject: Support Teltonika DSM camera --- .../traccar/protocol/DualcamProtocolDecoder.java | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index f6712d7f2..b0e793a43 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -46,11 +46,15 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_PATH_RESPONSE = 0x000D; private String uniqueId; - private int packetCount; - private int currentPacket; + private int dataSize; + private int dataCurrent; private boolean video; private ByteBuf media; + private boolean isPacketData() { + return dataSize < 100; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -97,21 +101,29 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { break; case MSG_START: buf.readUnsignedShort(); // length - packetCount = buf.readInt(); - currentPacket = 1; + dataSize = buf.readInt(); + dataCurrent = isPacketData() ? 1 : 0; media = Unpooled.buffer(); if (channel != null) { ByteBuf response = Unpooled.buffer(); response.writeShort(MSG_RESUME); response.writeShort(4); - response.writeInt(currentPacket); + response.writeInt(dataCurrent); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } break; case MSG_DATA: - buf.readUnsignedShort(); // length - media.writeBytes(buf, buf.readableBytes() - 2); - if (currentPacket == packetCount) { + int length = buf.readUnsignedShort(); + media.writeBytes(buf, length); + boolean finished; + if (isPacketData()) { + finished = dataCurrent == dataSize; + dataCurrent += 1; + } else { + finished = dataCurrent + length == dataSize; + dataCurrent += length; + } + if (finished) { deviceSession = getDeviceSession(channel, remoteAddress); Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -132,8 +144,6 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } return position; - } else { - currentPacket += 1; } break; case MSG_PATH_RESPONSE: -- cgit v1.2.3 From f159a96647c091f2234db6ad84203735251598c8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 26 Oct 2023 20:11:54 -0700 Subject: Fix data length --- src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index b0e793a43..1455519e5 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -63,11 +63,12 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { int type = buf.readUnsignedShort(); + DeviceSession deviceSession; switch (type) { case MSG_INIT: buf.readUnsignedShort(); // protocol id uniqueId = String.valueOf(buf.readLong()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); + deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); long settings = buf.readUnsignedInt(); if (channel != null && deviceSession != null) { ByteBuf response = Unpooled.buffer(); @@ -113,7 +114,7 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { } break; case MSG_DATA: - int length = buf.readUnsignedShort(); + int length = buf.readUnsignedShort() - 2; media.writeBytes(buf, length); boolean finished; if (isPacketData()) { -- cgit v1.2.3 From 3bb48d3b472a9434d1d228767fef1d692b070b8e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 26 Oct 2023 20:18:07 -0700 Subject: Fix coordinates filter (fix #5203) --- src/main/java/org/traccar/handler/DistanceHandler.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java index 7fdefa1f4..6bb774a15 100644 --- a/src/main/java/org/traccar/handler/DistanceHandler.java +++ b/src/main/java/org/traccar/handler/DistanceHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2015 Amila Silva * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,15 +36,15 @@ public class DistanceHandler extends BaseDataHandler { private final CacheManager cacheManager; private final boolean filter; - private final int coordinatesMinError; - private final int coordinatesMaxError; + private final int minError; + private final int maxError; @Inject public DistanceHandler(Config config, CacheManager cacheManager) { this.cacheManager = cacheManager; this.filter = config.getBoolean(Keys.COORDINATES_FILTER); - this.coordinatesMinError = config.getInteger(Keys.COORDINATES_MIN_ERROR); - this.coordinatesMaxError = config.getInteger(Keys.COORDINATES_MAX_ERROR); + this.minError = config.getInteger(Keys.COORDINATES_MIN_ERROR); + this.maxError = config.getInteger(Keys.COORDINATES_MAX_ERROR); } @Override @@ -66,8 +66,8 @@ public class DistanceHandler extends BaseDataHandler { distance = BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); } if (filter && last.getLatitude() != 0 && last.getLongitude() != 0) { - boolean satisfiesMin = coordinatesMinError == 0 || distance > coordinatesMinError; - boolean satisfiesMax = coordinatesMaxError == 0 || distance < coordinatesMaxError; + boolean satisfiesMin = minError == 0 || distance > minError; + boolean satisfiesMax = maxError == 0 || distance < maxError || position.getValid(); if (!satisfiesMin || !satisfiesMax) { position.setValid(last.getValid()); position.setLatitude(last.getLatitude()); -- cgit v1.2.3 From 0239cd47ed696a67d65661a1d936c925303f9b58 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 27 Oct 2023 07:21:22 -0700 Subject: Include P45 event source --- src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java index dc763dea7..1b6d471b4 100644 --- a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java @@ -386,7 +386,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { .expression("([AV]),") // validity .number("(d+),") // speed .number("(d+),") // course - .number("d+,") // event source + .number("(d+),") // event source .number("d+,") // unlock verification .number("(d+),") // rfid .number("d+,") // password verification @@ -419,6 +419,8 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble())); position.setCourse(parser.nextDouble()); + position.set("eventSource", parser.nextInt()); + String rfid = parser.next(); if (!rfid.equals("0000000000")) { position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); -- cgit v1.2.3 From 6878beaa6856c378b0df0c17b8a4c689fd752cfa Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 28 Oct 2023 07:47:18 -0700 Subject: Increase packet threshold --- src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index 1455519e5..801e8d22e 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -52,7 +52,7 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { private ByteBuf media; private boolean isPacketData() { - return dataSize < 100; + return dataSize < 1000; } @Override -- cgit v1.2.3 From 29b9ec9ddcd8248b8a8398a2c714a8f52c0581d8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 28 Oct 2023 20:32:09 -0700 Subject: Basic Positrex protocol support --- setup/default.xml | 1 + .../org/traccar/protocol/PositrexProtocol.java | 36 +++++++ .../traccar/protocol/PositrexProtocolDecoder.java | 106 +++++++++++++++++++++ .../protocol/PositrexProtocolDecoderTest.java | 20 ++++ 4 files changed, 163 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/PositrexProtocol.java create mode 100644 src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index c5992b087..5e28ea1a9 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -293,5 +293,6 @@ 5249 5250 5251 + 5252 diff --git a/src/main/java/org/traccar/protocol/PositrexProtocol.java b/src/main/java/org/traccar/protocol/PositrexProtocol.java new file mode 100644 index 000000000..67b8f2189 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PositrexProtocol.java @@ -0,0 +1,36 @@ +/* + * 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 jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class PositrexProtocol extends BaseProtocol { + + @Inject + public PositrexProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new PositrexProtocolDecoder(PositrexProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java new file mode 100644 index 000000000..8726bc831 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java @@ -0,0 +1,106 @@ +/* + * 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.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.util.Date; + +public class PositrexProtocolDecoder extends BaseProtocolDecoder { + + public PositrexProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_PING = 0x2E; + + private Date readTime(ByteBuf buf) { + long time = buf.readUnsignedInt(); + DateBuilder dateBuilder = new DateBuilder(); + dateBuilder.setSecond((int) (time % 60)); + time /= 60; + dateBuilder.setMinute((int) (time % 60)); + time /= 60; + dateBuilder.setHour((int) (time % 24)); + time /= 24; + dateBuilder.setDay((int) (time % 32)); + time /= 32; + dateBuilder.setMonth((int) (time % 13)); + dateBuilder.setYear((int) (2000 + time / 13)); + return dateBuilder.getDate(); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int first = buf.getUnsignedByte(buf.readerIndex()); + int second = buf.getUnsignedByte(buf.readerIndex() + 1); + long deviceId; + if (BitUtil.check(first, 7)) { + if (BitUtil.check(first, 6)) { + deviceId = 73000000 + BitUtil.to(buf.readUnsignedInt(), 30); + } else if (second == 0) { + deviceId = 7590000 + BitUtil.to(buf.readUnsignedMedium(), 20); + } else { + deviceId = 70000000 + BitUtil.to(buf.readUnsignedMedium(), 20); + } + } else { + deviceId = 7560000 + buf.readUnsignedShort(); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + if (deviceSession == null) { + return null; + } + + int service = buf.readUnsignedByte(); + if (service == MSG_PING) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(readTime(buf)); + + int latitude = buf.readMedium(); + int longitude = buf.readMedium(); + + position.setValid(BitUtil.check(latitude, 23)); + position.setLatitude(BitUtil.to(latitude, 23) * 0.000025); + position.setLongitude(longitude * 0.000025); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedByte() * 2); + + return position; + + } + + return null; + } + +} diff --git a/src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java new file mode 100644 index 000000000..ff9d3ee1b --- /dev/null +++ b/src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java @@ -0,0 +1,20 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class PositrexProtocolDecoderTest extends ProtocolTest { + + @Disabled + @Test + public void testDecode() throws Exception { + + var decoder = inject(new PositrexProtocolDecoder(null)); + + verifyPosition(decoder, binary( + "TODO")); + + } + +} -- cgit v1.2.3 From 2319e1c707eedd25b3ca88b6ee00f416031d22a3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 29 Oct 2023 13:49:22 -0700 Subject: Cleanup OpenID class --- .../java/org/traccar/database/OpenIdProvider.java | 87 +++++++++++----------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 312be8890..19780c68d 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -66,20 +66,20 @@ public class OpenIdProvider { private final Boolean force; private final ClientID clientId; private final ClientAuthentication clientAuth; - private URI callbackUrl; - private URI authUrl; - private URI tokenUrl; - private URI userInfoUrl; - private URI baseUrl; + private final URI callbackUrl; + private final URI authUrl; + private final URI tokenUrl; + private final URI userInfoUrl; + private final URI baseUrl; private final String adminGroup; private final String allowGroup; - private LoginService loginService; + private final LoginService loginService; @Inject - public OpenIdProvider( - Config config, LoginService loginService, HttpClient httpClient, ObjectMapper objectMapper - ) throws InterruptedException, IOException, URISyntaxException { + public OpenIdProvider(Config config, LoginService loginService, HttpClient httpClient, ObjectMapper objectMapper) + throws InterruptedException, IOException, URISyntaxException { + this.loginService = loginService; force = config.getBoolean(Keys.OPENID_FORCE); @@ -97,8 +97,7 @@ public class OpenIdProvider { String httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); - Map discoveryMap = objectMapper.readValue( - httpResponse, new TypeReference>() { }); + Map discoveryMap = objectMapper.readValue(httpResponse, new TypeReference<>() {}); authUrl = new URI((String) discoveryMap.get("authorization_endpoint")); tokenUrl = new URI((String) discoveryMap.get("token_endpoint")); @@ -132,18 +131,18 @@ public class OpenIdProvider { .toURI(); } - private OIDCTokenResponse getToken( - AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException { - AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); - TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); + private OIDCTokenResponse getToken(AuthorizationCode code) + throws IOException, ParseException, GeneralSecurityException { + AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl); + TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant); - HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send(); - TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse); - if (!token.indicatesSuccess()) { - throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); - } + HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send(); + TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse); + if (!token.indicatesSuccess()) { + throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider."); + } - return (OIDCTokenResponse) token.toSuccessResponse(); + return (OIDCTokenResponse) token.toSuccessResponse(); } private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException { @@ -161,40 +160,40 @@ public class OpenIdProvider { return userInfoResponse.toSuccessResponse().getUserInfo(); } - public URI handleCallback( - URI requestUri, HttpServletRequest request - ) throws StorageException, ParseException, IOException, GeneralSecurityException { - AuthorizationResponse response = AuthorizationResponse.parse(requestUri); + public URI handleCallback(URI requestUri, HttpServletRequest request) + throws StorageException, ParseException, IOException, GeneralSecurityException { + + AuthorizationResponse response = AuthorizationResponse.parse(requestUri); - if (!response.indicatesSuccess()) { - throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); - } + if (!response.indicatesSuccess()) { + throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription()); + } - AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); + AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode(); - if (authCode == null) { - throw new GeneralSecurityException("Malformed OpenID callback."); - } + if (authCode == null) { + throw new GeneralSecurityException("Malformed OpenID callback."); + } - OIDCTokenResponse tokens = getToken(authCode); + OIDCTokenResponse tokens = getToken(authCode); - BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); + BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken(); - UserInfo userInfo = getUserInfo(bearerToken); + UserInfo userInfo = getUserInfo(bearerToken); - List userGroups = userInfo.getStringListClaim("groups"); - Boolean administrator = adminGroup != null && userGroups.contains(adminGroup); + List userGroups = userInfo.getStringListClaim("groups"); + boolean administrator = adminGroup != null && userGroups.contains(adminGroup); - if (!(administrator || allowGroup == null || userGroups.contains(allowGroup))) { - throw new GeneralSecurityException("Your OpenID Groups do not permit access to Traccar."); - } + if (!(administrator || allowGroup == null || userGroups.contains(allowGroup))) { + throw new GeneralSecurityException("Your OpenID Groups do not permit access to Traccar."); + } - User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), administrator); + User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), administrator); - request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); + request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); - return baseUrl; + return baseUrl; } public boolean getForce() { -- cgit v1.2.3 From 468a9c22bea1421a5df5513766dd7709f1e05b04 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 29 Oct 2023 14:08:22 -0700 Subject: Fix lint issue --- src/main/java/org/traccar/database/OpenIdProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 19780c68d..1f5a2f481 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -97,7 +97,8 @@ public class OpenIdProvider { String httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); - Map discoveryMap = objectMapper.readValue(httpResponse, new TypeReference<>() {}); + Map discoveryMap = objectMapper.readValue(httpResponse, new TypeReference<>() { + }); authUrl = new URI((String) discoveryMap.get("authorization_endpoint")); tokenUrl = new URI((String) discoveryMap.get("token_endpoint")); -- cgit v1.2.3 From 3296318dccfcc83cc99d6da58affe5ee8a46fedb Mon Sep 17 00:00:00 2001 From: e-macgregor <122734173+e-macgregor@users.noreply.github.com> Date: Sun, 29 Oct 2023 17:20:36 -0600 Subject: totp --- build.gradle | 1 + schema/changelog-5.10.xml | 17 +++++++++++++ schema/changelog-master.xml | 1 + .../org/traccar/api/resource/SessionResource.java | 20 ++++++++++++---- .../org/traccar/api/resource/UserResource.java | 16 +++++++++++++ .../api/security/CodeRequiredException.java | 22 +++++++++++++++++ .../org/traccar/api/security/LoginService.java | 28 +++++++++++++++------- .../api/security/SecurityRequestFilter.java | 2 +- src/main/java/org/traccar/config/Keys.java | 14 +++++++++++ src/main/java/org/traccar/model/User.java | 10 ++++++++ 10 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 schema/changelog-5.10.xml create mode 100644 src/main/java/org/traccar/api/security/CodeRequiredException.java diff --git a/build.gradle b/build.gradle index 2e8b557ba..75fe792b0 100644 --- a/build.gradle +++ b/build.gradle @@ -90,6 +90,7 @@ dependencies { implementation "com.google.firebase:firebase-admin:9.2.0" implementation "com.nimbusds:oauth2-oidc-sdk:10.13.2" implementation "com.rabbitmq:amqp-client:5.18.0" + implementation "com.warrenstrange:googleauth:1.2.0" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testImplementation "org.mockito:mockito-core:5.4.0" diff --git a/schema/changelog-5.10.xml b/schema/changelog-5.10.xml new file mode 100644 index 000000000..63988b14a --- /dev/null +++ b/schema/changelog-5.10.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index 331d5ec78..183b3fd93 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -40,5 +40,6 @@ + diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 3e738c15a..90f0ceade 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -16,6 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; +import org.traccar.api.security.CodeRequiredException; import org.traccar.api.security.LoginService; import org.traccar.api.signature.TokenManager; import org.traccar.database.OpenIdProvider; @@ -108,7 +109,7 @@ public class SessionResource extends BaseResource { } } if (email != null && password != null) { - User user = loginService.login(email, password); + User user = loginService.login(email, password, null); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); @@ -142,8 +143,19 @@ public class SessionResource extends BaseResource { @PermitAll @POST public User add( - @FormParam("email") String email, @FormParam("password") String password) throws StorageException { - User user = loginService.login(email, password); + @FormParam("email") String email, + @FormParam("password") String password, + @FormParam("code") Integer code) throws StorageException { + User user; + try { + user = loginService.login(email, password, code); + } catch (CodeRequiredException e) { + Response response = Response + .status(Response.Status.UNAUTHORIZED) + .header("WWW-Authenticate", "TOTP") + .build(); + throw new WebApplicationException(response); + } if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); @@ -171,7 +183,7 @@ public class SessionResource extends BaseResource { @PermitAll @Path("openid/auth") @GET - public Response openIdAuth() throws IOException { + public Response openIdAuth() { return Response.seeOther(openIdProvider.createAuthUri()).build(); } diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index d73e8b6f5..99537f912 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -15,12 +15,14 @@ */ package org.traccar.api.resource; +import com.warrenstrange.googleauth.GoogleAuthenticator; 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.config.Keys; import org.traccar.helper.LogAction; import org.traccar.helper.model.UserUtil; import org.traccar.model.ManagedUser; @@ -96,6 +98,10 @@ public class UserResource extends BaseObjectResource { if (!permissionsService.getServer().getRegistration()) { throw new SecurityException("Registration disabled"); } + if (permissionsService.getServer().getBoolean(Keys.WEB_TOTP_FORCE.getKey()) + && entity.getTotpKey() == null) { + throw new SecurityException("One-time password key is required"); + } UserUtil.setUserDefaults(entity, config); } } @@ -128,4 +134,14 @@ public class UserResource extends BaseObjectResource { return response; } + @Path("totp") + @PermitAll + @POST + public String generateTotpKey() throws StorageException { + if (!permissionsService.getServer().getBoolean(Keys.WEB_TOTP_ENABLE.getKey())) { + throw new SecurityException("One-time password is disabled"); + } + return new GoogleAuthenticator().createCredentials().getKey(); + } + } diff --git a/src/main/java/org/traccar/api/security/CodeRequiredException.java b/src/main/java/org/traccar/api/security/CodeRequiredException.java new file mode 100644 index 000000000..d522c6540 --- /dev/null +++ b/src/main/java/org/traccar/api/security/CodeRequiredException.java @@ -0,0 +1,22 @@ +/* + * 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.api.security; + +public class CodeRequiredException extends SecurityException { + public CodeRequiredException() { + super("Code not provided"); + } +} diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 91e964ee9..8eb5537fa 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -15,6 +15,7 @@ */ package org.traccar.api.security; +import com.warrenstrange.googleauth.GoogleAuthenticator; import org.traccar.api.signature.TokenManager; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -70,7 +71,7 @@ public class LoginService { return user; } - public User login(String email, String password) throws StorageException { + public User login(String email, String password, Integer code) throws StorageException { if (forceOpenId) { return null; } @@ -84,6 +85,7 @@ public class LoginService { if (user != null) { if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) || !forceLdap && user.isPasswordValid(password)) { + checkUserCode(user, code); checkUserEnabled(user); return user; } @@ -98,15 +100,12 @@ public class LoginService { return null; } - public User login(String email, String name, Boolean administrator) throws StorageException { + public User login(String email, String name, boolean administrator) throws StorageException { User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Equals("email", email))); - if (user != null) { - checkUserEnabled(user); - return user; - } else { + if (user == null) { user = new User(); UserUtil.setUserDefaults(user, config); user.setName(name); @@ -114,9 +113,9 @@ public class LoginService { user.setFixedEmail(true); user.setAdministrator(administrator); user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); - checkUserEnabled(user); - return user; } + checkUserEnabled(user); + return user; } private void checkUserEnabled(User user) throws SecurityException { @@ -126,4 +125,17 @@ public class LoginService { user.checkDisabled(); } + private void checkUserCode(User user, Integer code) throws SecurityException { + String key = user.getTotpKey(); + if (key != null) { + if (code == null) { + throw new CodeRequiredException(); + } + GoogleAuthenticator authenticator = new GoogleAuthenticator(); + if (!authenticator.authorize(key, code)) { + throw new SecurityException("User authorization failed"); + } + } + } + } diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index ee964c9e4..cb523177e 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -87,7 +87,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { user = loginService.login(authHeader.substring(7)); } else { String[] auth = decodeBasicAuth(authHeader); - user = loginService.login(auth[0], auth[1]); + user = loginService.login(auth[0], auth[1], null); } if (user != null) { statisticsManager.registerRequest(user.getId()); diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 91063a8e0..48dec863d 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -837,6 +837,20 @@ public final class Keys { List.of(KeyType.CONFIG), "max-age=3600,public"); + /** + * Enable TOTP authentication on the server. + */ + public static final ConfigKey WEB_TOTP_ENABLE = new BooleanConfigKey( + "totpEnable", + List.of(KeyType.SERVER)); + + /** + * Server attribute that indicates that TOTP authentication is required for new users. + */ + public static final ConfigKey WEB_TOTP_FORCE = new BooleanConfigKey( + "totpForce", + List.of(KeyType.SERVER)); + /** * Host for raw data forwarding. */ diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 0540f16d7..757064ba2 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -251,6 +251,16 @@ public class User extends ExtendedModel implements UserRestrictions, Disableable this.poiLayer = poiLayer; } + private String totpKey; + + public String getTotpKey() { + return totpKey; + } + + public void setTotpKey(String totpKey) { + this.totpKey = totpKey; + } + @QueryIgnore public String getPassword() { return null; -- cgit v1.2.3 From 1db5f2aac51279c65ff2b983923452c6f4bad4e9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 29 Oct 2023 20:29:46 -0700 Subject: Better DSM detection --- src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index 801e8d22e..75cd52384 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.model.Device; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -45,6 +46,7 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_PATH_REQUEST = 0x000C; public static final int MSG_PATH_RESPONSE = 0x000D; + private String model; private String uniqueId; private int dataSize; private int dataCurrent; @@ -52,7 +54,11 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { private ByteBuf media; private boolean isPacketData() { - return dataSize < 1000; + if (model == null) { + return dataSize < 8192; + } else { + return !"DSM".equals(model); + } } @Override @@ -71,6 +77,7 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); long settings = buf.readUnsignedInt(); if (channel != null && deviceSession != null) { + model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); ByteBuf response = Unpooled.buffer(); if (BitUtil.check(settings, 25)) { response.writeShort(MSG_PATH_REQUEST); -- cgit v1.2.3 From ecd06b48972f6f7390c4b133e1244a7f8f61f844 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 30 Oct 2023 07:39:56 -0700 Subject: OBD speed in km/h units --- src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 4 +--- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java index 4d8e7e7ea..d0402cc94 100644 --- a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java @@ -165,7 +165,7 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RPM, Integer.parseInt(value)); break; case 0x10d: - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(value))); + position.set(Position.KEY_OBD_SPEED, Integer.parseInt(value)); break; case 0x111: position.set(Position.KEY_THROTTLE, Integer.parseInt(value)); diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 911af8d73..530ab836a 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -422,7 +422,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RPM, Integer.parseInt(values[index - 1])); } if (BitUtil.check(reportMask, 4) && !values[index++].isEmpty()) { - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); + position.set(Position.KEY_OBD_SPEED, Integer.parseInt(values[index - 1])); } if (BitUtil.check(reportMask, 6) && !values[index++].isEmpty()) { position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index - 1])); diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index ffcaa0c6c..cd7ffa0e1 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -375,9 +375,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 69: value = buf.readUnsignedByte(); - position.set( - Position.KEY_OBD_SPEED, - (value != 0xFF) ? UnitsConverter.knotsFromKph(value) : null); + position.set(Position.KEY_OBD_SPEED, (value != 0xFF) ? value : null); break; case 78: case 79: diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index d4f9808ae..cde626c5f 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -150,7 +150,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { } break; case 95: - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(readValue(buf, length, true))); + position.set(Position.KEY_OBD_SPEED, readValue(buf, length, true)); break; case 134: if (readValue(buf, length, false) > 0) { diff --git a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java index edcb3f535..11f9e0654 100644 --- a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java @@ -177,7 +177,7 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); break; case 0x57: - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort()); break; case 0x65: position.set(Position.KEY_VIN, buf.readSlice(17).toString(StandardCharsets.US_ASCII)); -- cgit v1.2.3 From d4c4daa491ae70d608b3e791f4ad8b07ced43437 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 30 Oct 2023 08:42:21 -0700 Subject: Update Position.java --- src/main/java/org/traccar/model/Position.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 6685cab95..39f63217d 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -95,7 +95,7 @@ public class Position extends Message { public static final String KEY_DRIVING_TIME = "drivingTime"; public static final String KEY_DTCS = "dtcs"; - public static final String KEY_OBD_SPEED = "obdSpeed"; // knots + public static final String KEY_OBD_SPEED = "obdSpeed"; // km/h public static final String KEY_OBD_ODOMETER = "obdOdometer"; // meters public static final String KEY_RESULT = "result"; -- cgit v1.2.3 From 38bea83f8d52675b1d211d972ac419fb208d198b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 2 Nov 2023 07:01:44 -0700 Subject: Handle empty TOTP field --- src/main/java/org/traccar/api/security/LoginService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 8eb5537fa..829f5d2fa 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -127,7 +127,7 @@ public class LoginService { private void checkUserCode(User user, Integer code) throws SecurityException { String key = user.getTotpKey(); - if (key != null) { + if (key != null && !key.isEmpty()) { if (code == null) { throw new CodeRequiredException(); } -- cgit v1.2.3 From cf01dea0bd1ddb1cb9df402a4ce079cf5d9df0bd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 3 Nov 2023 07:30:17 -0700 Subject: Update Positrex to use UDP --- src/main/java/org/traccar/protocol/PositrexProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/PositrexProtocol.java b/src/main/java/org/traccar/protocol/PositrexProtocol.java index 67b8f2189..5cf389fbe 100644 --- a/src/main/java/org/traccar/protocol/PositrexProtocol.java +++ b/src/main/java/org/traccar/protocol/PositrexProtocol.java @@ -25,7 +25,7 @@ public class PositrexProtocol extends BaseProtocol { @Inject public PositrexProtocol(Config config) { - addServer(new TrackerServer(config, getName(), false) { + addServer(new TrackerServer(config, getName(), true) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new PositrexProtocolDecoder(PositrexProtocol.this)); -- cgit v1.2.3 From 3860e965c9feede1ac876261a47370b44181b5d7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 Nov 2023 07:51:14 -0700 Subject: Support Dragino gateway protocol --- setup/default.xml | 1 + .../java/org/traccar/protocol/DraginoProtocol.java | 42 ++++++++++++ .../traccar/protocol/DraginoProtocolDecoder.java | 78 ++++++++++++++++++++++ .../protocol/DraginoProtocolDecoderTest.java | 20 ++++++ 4 files changed, 141 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/DraginoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/DraginoProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/DraginoProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index 5e28ea1a9..48fd8c993 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -294,5 +294,6 @@ 5250 5251 5252 + 5253 diff --git a/src/main/java/org/traccar/protocol/DraginoProtocol.java b/src/main/java/org/traccar/protocol/DraginoProtocol.java new file mode 100644 index 000000000..d33efe2ad --- /dev/null +++ b/src/main/java/org/traccar/protocol/DraginoProtocol.java @@ -0,0 +1,42 @@ +/* + * 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.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class DraginoProtocol extends BaseProtocol { + + @Inject + public DraginoProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new DraginoProtocolDecoder(DraginoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/DraginoProtocolDecoder.java b/src/main/java/org/traccar/protocol/DraginoProtocolDecoder.java new file mode 100644 index 000000000..5f576d723 --- /dev/null +++ b/src/main/java/org/traccar/protocol/DraginoProtocolDecoder.java @@ -0,0 +1,78 @@ +/* + * 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.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.DateUtil; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class DraginoProtocolDecoder extends BaseHttpProtocolDecoder { + + public DraginoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String content = request.content().toString(StandardCharsets.UTF_8); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + String deviceId = json.getJsonObject("end_device_ids").getString("device_id"); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + JsonObject message = json.getJsonObject("uplink_message"); + JsonObject decoded = message.getJsonObject("decoded_payload"); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(DateUtil.parseDate(message.getString("received_at"))); + + position.setValid(true); + position.setLatitude(decoded.getJsonNumber("Latitude").doubleValue()); + position.setLongitude(decoded.getJsonNumber("Longitude").doubleValue()); + + position.set("humidity", decoded.getJsonNumber("Hum").doubleValue()); + position.set(Position.KEY_BATTERY, decoded.getJsonNumber("BatV").doubleValue()); + position.set(Position.PREFIX_TEMP + 1, decoded.getJsonNumber("Tem").doubleValue()); + + if (Boolean.parseBoolean(decoded.getString("ALARM_status"))) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + + sendResponse(channel, HttpResponseStatus.OK); + return position; + } + +} diff --git a/src/test/java/org/traccar/protocol/DraginoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DraginoProtocolDecoderTest.java new file mode 100644 index 000000000..26de75141 --- /dev/null +++ b/src/test/java/org/traccar/protocol/DraginoProtocolDecoderTest.java @@ -0,0 +1,20 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class DraginoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new DraginoProtocolDecoder(null)); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"end_device_ids\":{\"device_id\":\"eui-a840412b81874509\",\"application_ids\":{\"application_id\":\"teast12344321\"},\"dev_eui\":\"A840412B81874509\",\"join_eui\":\"A840410000000102\",\"dev_addr\":\"260BB59A\"},\"correlation_ids\":[\"gs:uplink:01HDTGK4QWSRX0AMP8E6R1R809\"],\"received_at\":\"2023-10-28T06:47:23.853335601Z\",\"uplink_message\":{\"session_key_id\":\"AYt1CUoFjSPmZ+/Hf8bbng==\",\"f_port\":2,\"f_cnt\":1,\"frm_payload\":\"AAAAAAAAAAAPoiACpwEQ\",\"decoded_payload\":{\"ALARM_status\":\"FALSE\",\"BatV\":4.002,\"Hum\":67.9,\"LON\":\"ON\",\"Latitude\":0,\"Location\":0,\"Longitude\":0,\"MD\":0,\"Tem\":27.2},\"rx_metadata\":[{\"gateway_ids\":{\"gateway_id\":\"eui-a840411b7c4c4150\",\"eui\":\"A840411B7C4C4150\"},\"time\":\"2023-10-28T06:47:23.522309Z\",\"timestamp\":2618357987,\"rssi\":-101,\"channel_rssi\":-101,\"snr\":8.5,\"uplink_token\":\"CiIKIAoUZXVpLWE4NDA0MTFiN2M0YzQxNTASCKhAQRt8TEFQEOPxw+AJGgwI+9zyqQYQ+LGJswIguO2wkpqnNg==\",\"received_at\":\"2023-10-28T06:47:23.643979512Z\"},{\"gateway_ids\":{\"gateway_id\":\"test123123\",\"eui\":\"A840411D178C4150\"},\"time\":\"2023-10-28T06:47:23.522842Z\",\"timestamp\":3064971227,\"rssi\":-78,\"channel_rssi\":-78,\"snr\":8.8,\"uplink_token\":\"ChgKFgoKdGVzdDEyMzEyMxIIqEBBHReMQVAQ2/++tQsaDAj73PKpBhDyj+e1AiD43pX0ma44\",\"received_at\":\"2023-10-28T06:47:23.649709554Z\"},{\"gateway_ids\":{\"gateway_id\":\"eui-b8ea26fdfe2d5d28\",\"eui\":\"B8EA26FDFE2D5D28\"},\"time\":\"2023-10-28T06:47:23.536703Z\",\"timestamp\":2967400725,\"rssi\":-38,\"channel_rssi\":-38,\"snr\":14.2,\"frequency_offset\":\"1061\",\"uplink_token\":\"CiIKIAoUZXVpLWI4ZWEyNmZkZmUyZDVkMjgSCLjqJv3+LV0oEJXi+4YLGgwI+9zyqQYQxqentwIgiPT2tq60NQ==\",\"received_at\":\"2023-10-28T06:47:23.532394512Z\"},{\"gateway_ids\":{\"gateway_id\":\"eu868-1\",\"eui\":\"A840411B7E5E1868\"},\"time\":\"2023-10-28T06:47:23.526195Z\",\"timestamp\":3486064627,\"rssi\":-35,\"channel_rssi\":-35,\"snr\":9,\"uplink_token\":\"ChUKEwoHZXU4NjgtMRIIqEBBG35eGGgQ87+k/gwaDAj73PKpBhDZzuW4AiC4mpPNusM1\",\"received_at\":\"2023-10-28T06:47:23.537018603Z\"}],\"settings\":{\"data_rate\":{\"lora\":{\"bandwidth\":125000,\"spreading_factor\":7,\"coding_rate\":\"4/5\"}},\"frequency\":\"868100000\",\"timestamp\":2618357987,\"time\":\"2023-10-28T06:47:23.522309Z\"},\"received_at\":\"2023-10-28T06:47:23.644805734Z\",\"consumed_airtime\":\"0.066816s\",\"network_ids\":{\"net_id\":\"000013\",\"ns_id\":\"EC656E0000000181\",\"tenant_id\":\"ttn\",\"cluster_id\":\"eu1\",\"cluster_address\":\"eu1.cloud.thethings.network\"}}}"))); + + } + +} -- cgit v1.2.3 From 1b7802c639f8d40db141429f2c15b96e3b743a04 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 6 Nov 2023 06:38:30 -0800 Subject: Fix device id decoding --- src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java | 3 +-- src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java index 8726bc831..ff4825e8d 100644 --- a/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java @@ -59,12 +59,11 @@ public class PositrexProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; int first = buf.getUnsignedByte(buf.readerIndex()); - int second = buf.getUnsignedByte(buf.readerIndex() + 1); long deviceId; if (BitUtil.check(first, 7)) { if (BitUtil.check(first, 6)) { deviceId = 73000000 + BitUtil.to(buf.readUnsignedInt(), 30); - } else if (second == 0) { + } else if (!BitUtil.check(first, 5) && !BitUtil.check(first, 4)) { deviceId = 7590000 + BitUtil.to(buf.readUnsignedMedium(), 20); } else { deviceId = 70000000 + BitUtil.to(buf.readUnsignedMedium(), 20); diff --git a/src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java index ff9d3ee1b..bf4f9c765 100644 --- a/src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PositrexProtocolDecoderTest.java @@ -1,19 +1,17 @@ package org.traccar.protocol; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; public class PositrexProtocolDecoderTest extends ProtocolTest { - @Disabled @Test public void testDecode() throws Exception { var decoder = inject(new PositrexProtocolDecoder(null)); verifyPosition(decoder, binary( - "TODO")); + "8280902e002b81c99fd607033905008b1c000003ae00003c9c000054ee00000079000000000d34d43f0fffffffda0000000000104fb80000204086464717807f8931082622128190980fffff862261047296590fffff")); } -- cgit v1.2.3 From d57af42117c98a0c52d9bd776aa8d24af2dfafeb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 9 Nov 2023 06:31:50 -0800 Subject: Add Fifotrack alarm code --- src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index 87587aa1e..95b7e2733 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -183,6 +183,8 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { case 30: case 32: return Position.ALARM_JAMMING; + case 31: + return Position.ALARM_FALL_DOWN; case 33: return Position.ALARM_GEOFENCE_EXIT; case 34: -- cgit v1.2.3 From cd5413ae082a55e94d46f38a2a73f72eddb92aca Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 9 Nov 2023 07:55:45 -0800 Subject: Update HERE geocoder --- src/main/java/org/traccar/MainModule.java | 3 +- src/main/java/org/traccar/config/Keys.java | 7 --- .../java/org/traccar/geocoder/HereGeocoder.java | 58 ++++++++++------------ .../java/org/traccar/geocoder/GeocoderTest.java | 4 +- 4 files changed, 29 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 9559b3a90..3fec4d1e6 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -200,7 +200,6 @@ public class MainModule extends AbstractModule { if (config.getBoolean(Keys.GEOCODER_ENABLE)) { String type = config.getString(Keys.GEOCODER_TYPE, "google"); String url = config.getString(Keys.GEOCODER_URL); - String id = config.getString(Keys.GEOCODER_ID); String key = config.getString(Keys.GEOCODER_KEY); String language = config.getString(Keys.GEOCODER_LANGUAGE); String formatString = config.getString(Keys.GEOCODER_FORMAT); @@ -243,7 +242,7 @@ public class MainModule extends AbstractModule { geocoder = new BanGeocoder(client, cacheSize, addressFormat); break; case "here": - geocoder = new HereGeocoder(client, url, id, key, language, cacheSize, addressFormat); + geocoder = new HereGeocoder(client, url, key, language, cacheSize, addressFormat); break; case "mapmyindia": geocoder = new MapmyIndiaGeocoder(client, url, key, cacheSize, addressFormat); diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 48dec863d..e7b07791f 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1553,13 +1553,6 @@ public final class Keys { "geocoder.url", List.of(KeyType.CONFIG)); - /** - * App id for use with Here provider. - */ - public static final ConfigKey GEOCODER_ID = new StringConfigKey( - "geocoder.id", - List.of(KeyType.CONFIG)); - /** * Provider API key. Most providers require API keys. */ diff --git a/src/main/java/org/traccar/geocoder/HereGeocoder.java b/src/main/java/org/traccar/geocoder/HereGeocoder.java index 2d1bc1bf4..4767eabad 100644 --- a/src/main/java/org/traccar/geocoder/HereGeocoder.java +++ b/src/main/java/org/traccar/geocoder/HereGeocoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -20,65 +20,59 @@ import jakarta.ws.rs.client.Client; public class HereGeocoder extends JsonGeocoder { - private static String formatUrl(String url, String id, String key, String language) { + private static String formatUrl(String url, String key, String language) { if (url == null) { - url = "https://reverse.geocoder.ls.hereapi.com/6.2/reversegeocode.json"; + url = "https://revgeocode.search.hereapi.com/v1/revgeocode"; } - url += "?mode=retrieveAddresses&maxresults=1"; - url += "&prox=%f,%f,0"; - url += "&app_id=" + id; - url += "&app_code=" + key; + url += "?types=address&limit=1"; + url += "&at=%f,%f"; url += "&apiKey=" + key; if (language != null) { - url += "&language=" + language; + url += "&lang=" + language; } return url; } public HereGeocoder( - Client client, String url, String id, String key, String language, + Client client, String url, String key, String language, int cacheSize, AddressFormat addressFormat) { - super(client, formatUrl(url, id, key, language), cacheSize, addressFormat); + super(client, formatUrl(url, key, language), cacheSize, addressFormat); } @Override public Address parseAddress(JsonObject json) { JsonObject result = json - .getJsonObject("Response") - .getJsonArray("View") + .getJsonArray("items") .getJsonObject(0) - .getJsonArray("Result") - .getJsonObject(0) - .getJsonObject("Location") - .getJsonObject("Address"); + .getJsonObject("address"); if (result != null) { Address address = new Address(); - if (result.containsKey("Label")) { - address.setFormattedAddress(result.getString("Label")); + if (result.containsKey("label")) { + address.setFormattedAddress(result.getString("label")); } - if (result.containsKey("HouseNumber")) { - address.setHouse(result.getString("HouseNumber")); + if (result.containsKey("houseNumber")) { + address.setHouse(result.getString("houseNumber")); } - if (result.containsKey("Street")) { - address.setStreet(result.getString("Street")); + if (result.containsKey("street")) { + address.setStreet(result.getString("street")); } - if (result.containsKey("City")) { - address.setSettlement(result.getString("City")); + if (result.containsKey("city")) { + address.setSettlement(result.getString("city")); } - if (result.containsKey("District")) { - address.setDistrict(result.getString("District")); + if (result.containsKey("district")) { + address.setDistrict(result.getString("district")); } - if (result.containsKey("State")) { - address.setState(result.getString("State")); + if (result.containsKey("state")) { + address.setState(result.getString("state")); } - if (result.containsKey("Country")) { - address.setCountry(result.getString("Country").toUpperCase()); + if (result.containsKey("countryCode")) { + address.setCountry(result.getString("countryCode").toUpperCase()); } - if (result.containsKey("PostalCode")) { - address.setPostcode(result.getString("PostalCode")); + if (result.containsKey("postalCode")) { + address.setPostcode(result.getString("postalCode")); } return address; diff --git a/src/test/java/org/traccar/geocoder/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java index 1e1a98c1e..ef2dd062d 100644 --- a/src/test/java/org/traccar/geocoder/GeocoderTest.java +++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java @@ -77,9 +77,9 @@ public class GeocoderTest { @Disabled @Test public void testHere() { - Geocoder geocoder = new HereGeocoder(client, null, "", "", null, 0, new AddressFormat()); + Geocoder geocoder = new HereGeocoder(client, null, "aDc9qgsCpRbO9ioJIIAXzF6JYU7w8H5O260e9hsGrms", null, 0, new AddressFormat()); String address = geocoder.getAddress(48.8575, 2.2944, null); - assertEquals("6 Avenue Gustave Eiffel, Paris, Île-de-France, FRA", address); + assertEquals("1 Tour Eiffel, Paris, Île-de-France, FRA", address); } @Disabled -- cgit v1.2.3 From 3aa0729fba832e13da2fd0a6a1c600636fa235a9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 14 Nov 2023 07:35:45 -0800 Subject: Prefer used fuel attribute --- .../java/org/traccar/handler/DistanceHandler.java | 16 ++++++---------- .../org/traccar/reports/common/ReportUtils.java | 21 ++++++++------------- src/test/java/org/traccar/ProtocolTest.java | 4 ++++ 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java index 6bb774a15..db8c73779 100644 --- a/src/main/java/org/traccar/handler/DistanceHandler.java +++ b/src/main/java/org/traccar/handler/DistanceHandler.java @@ -17,6 +17,8 @@ package org.traccar.handler; import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.traccar.BaseDataHandler; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -24,11 +26,6 @@ import org.traccar.helper.DistanceCalculator; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.math.BigDecimal; -import java.math.RoundingMode; - @Singleton @ChannelHandler.Sharable public class DistanceHandler extends BaseDataHandler { @@ -54,8 +51,7 @@ public class DistanceHandler extends BaseDataHandler { if (position.hasAttribute(Position.KEY_DISTANCE)) { distance = position.getDouble(Position.KEY_DISTANCE); } - double totalDistance = 0.0; - + double totalDistance; Position last = cacheManager.getPosition(position.getDeviceId()); if (last != null) { totalDistance = last.getDouble(Position.KEY_TOTAL_DISTANCE); @@ -63,7 +59,6 @@ public class DistanceHandler extends BaseDataHandler { distance = DistanceCalculator.distance( position.getLatitude(), position.getLongitude(), last.getLatitude(), last.getLongitude()); - distance = BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); } if (filter && last.getLatitude() != 0 && last.getLongitude() != 0) { boolean satisfiesMin = minError == 0 || distance > minError; @@ -75,10 +70,11 @@ public class DistanceHandler extends BaseDataHandler { distance = 0; } } + } else { + totalDistance = 0.0; } position.set(Position.KEY_DISTANCE, distance); - totalDistance = BigDecimal.valueOf(totalDistance + distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); - position.set(Position.KEY_TOTAL_DISTANCE, totalDistance); + position.set(Position.KEY_TOTAL_DISTANCE, totalDistance + distance); return position; } diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 43db82708..3b8e84887 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,6 +16,8 @@ */ package org.traccar.reports.common; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.tools.generic.DateTool; import org.apache.velocity.tools.generic.NumberTool; @@ -52,13 +54,9 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import jakarta.annotation.Nullable; -import jakarta.inject.Inject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.math.BigDecimal; -import java.math.RoundingMode; import java.time.Duration; import java.util.ArrayList; import java.util.Date; @@ -102,14 +100,11 @@ public class ReportUtils { } } - public double calculateFuel(Position firstPosition, Position lastPosition) { - - if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null - && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) { - - BigDecimal value = BigDecimal.valueOf(firstPosition.getDouble(Position.KEY_FUEL_LEVEL) - - lastPosition.getDouble(Position.KEY_FUEL_LEVEL)); - return value.setScale(1, RoundingMode.HALF_EVEN).doubleValue(); + public double calculateFuel(Position first, Position last) { + if (first.hasAttribute(Position.KEY_FUEL_USED) && last.hasAttribute(Position.KEY_FUEL_USED)) { + return last.getDouble(Position.KEY_FUEL_USED) - first.getDouble(Position.KEY_FUEL_USED); + } else if (first.hasAttribute(Position.KEY_FUEL_LEVEL) && last.hasAttribute(Position.KEY_FUEL_LEVEL)) { + return first.getDouble(Position.KEY_FUEL_LEVEL) - last.getDouble(Position.KEY_FUEL_LEVEL); } return 0; } diff --git a/src/test/java/org/traccar/ProtocolTest.java b/src/test/java/org/traccar/ProtocolTest.java index 3b04b5e02..23ba562f8 100644 --- a/src/test/java/org/traccar/ProtocolTest.java +++ b/src/test/java/org/traccar/ProtocolTest.java @@ -261,6 +261,10 @@ public class ProtocolTest extends BaseTest { assertTrue(attributes.get(Position.KEY_FUEL_LEVEL) instanceof Number); } + if (attributes.containsKey(Position.KEY_FUEL_USED)) { + assertTrue(attributes.get(Position.KEY_FUEL_USED) instanceof Number); + } + if (attributes.containsKey(Position.KEY_POWER)) { assertTrue(attributes.get(Position.KEY_POWER) instanceof Number); } -- cgit v1.2.3 From e398778abace08beb3b6eea2de210b000944548e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 15 Nov 2023 06:01:04 -0800 Subject: Fix Mictrack MT710 wifi decoding --- src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java | 5 ++++- src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index e85bdf9b3..5ba053df3 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -78,8 +78,9 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_WIFI = new PatternBuilder() .text("#") .number("(?:(dd)|x+)") // cell or voltage + .expression("#?") .groupBegin() - .number("#(d+),") // mcc + .number("(d+),") // mcc .number("(d+),") // mnc .number("(x+),") // lac .number("(x+)") // cell id @@ -230,6 +231,8 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); getLastLocation(position, dateBuilder.getDate()); + } else { + continue; } } else { diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java index 46dc031a3..63aa3ebc0 100644 --- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tlt2hProtocolDecoder(null)); + verifyPositions(decoder, false, text( + "#862255061825896#MT710#0000#TOWED#1\r\n", + "#39#$WIFI,015259.00,A,-47,7483C2DBC0B0,-48,7683C2ABC0B0,-48,7683C29BC0B0,-48,7683C2CBC0B0,-48,7683C2BBC0B0,151123*74\r\n")); + verifyNull(decoder, text( "#860517049471362#MT700#0000#AUTO#1\r\n", "#36$GPRMC,,V,,,,,,,,,,A*5C\r\n")); -- cgit v1.2.3 From 88fdb4e19ba4f4f13deaefa64af1c5ad6896e655 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 15 Nov 2023 07:43:01 -0800 Subject: Add Lantrix t-1700 test case --- src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java index bc5901fb0..2858248bd 100644 --- a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class TaipProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TaipProtocolDecoder(null)); + verifyNull(decoder, text( + ">RTT151123153149-4330468-06503640000009300DF2101 04101203 000 00000000130000040414;ID=8803;#1ABD;*2B<")); + verifyAttribute(decoder, text( ">RUS00,111220124402-3138067-06417623000012200FF,000000000000000000000000000,0000000111,15640422,00000,+25.5,00000,51;ID=CST3G0443;#IP1:089F;*34<"), Position.PREFIX_TEMP + 1, 25.5); -- cgit v1.2.3 From 53de5422119c993d3fe8ed5b476c65cc01d340c5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 16 Nov 2023 07:13:24 -0800 Subject: Add Meitrack T633L fuel level --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 506ad2179..ea3302c30 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -471,6 +471,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x1A: position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); break; + case 0x29: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShortLE() * 0.01); + break; case 0x40: position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); break; -- cgit v1.2.3 From 962371fe50c9f2189ee5452def16c6fbd09a63f5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 17 Nov 2023 07:11:20 -0800 Subject: Support Queclink GT501MA devices --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 25 +++++++++++++++++++--- .../protocol/Gl200TextProtocolDecoderTest.java | 4 ++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 530ab836a..a4ace7a1c 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -260,7 +260,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private void skipLocation(Parser parser) { - parser.skip(19); + parser.skip(20); } private static final Pattern PATTERN_LOCATION = new PatternBuilder() @@ -272,6 +272,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .number("(-?d{1,2}.d{6})?,") // latitude .number("(dddd)(dd)(dd)") // date (yyyymmdd) .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .groupBegin() + .number(",d+") // wifi count + .number("((?:,x{12},-d+,,,)+)") // wifi + .groupEnd("?") .text(",") .number("(d+)?,") // mcc .number("(d+)?,") // mnc @@ -303,17 +307,32 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); } + Network network = new Network(); + + if (parser.hasNext()) { + String[] values = parser.next().split(","); + for (int i = 0; i < values.length; i += 5) { + String mac = values[i + 1].replaceAll("(..)", "$1:"); + network.addWifiAccessPoint(WifiAccessPoint.from( + mac.substring(0, mac.length() - 1), Integer.parseInt(values[i + 2]))); + } + } + if (parser.hasNext(6)) { int mcc = parser.nextInt(); int mnc = parser.nextInt(); if (parser.hasNext(2)) { - position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt()))); + network.addCellTower(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt())); } if (parser.hasNext(2)) { - position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt()))); + network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt())); } } + if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) { + position.setNetwork(network); + } + if (parser.hasNext()) { position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); } diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 3f8a4d0c2..a23b87fe5 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+RESP:GTFRI,423037,866884047716519,GT501,0,1,1,5,12,0.1,0,46.8,-95.559173,30.109955,20231110185836,6,0e36c9916485,-50,,,,e831cd5eb79d,-73,,,,ccf4110c4bd5,-79,,,,acdb48973168,-79,,,,80ab4dc323c4,-82,,,,ec8eb5cfa1c6,-89,,,,310,10,711D,81ECF0F,00,,93,20231110185839,0005$"), + Position.KEY_BATTERY_LEVEL, 93); + verifyNull(decoder, buffer( "+RESP:GTFRI,8020040200,866314060109269,,,10,1,1,0.0,0,9.0,-71.596601,-33.524595,20230722145338,0730,0001,772A,052B253E,00,0.0,,,,,100,210100,,,,20230722145341,0F4C$")); -- cgit v1.2.3 From e62f2e19b8f07af2a37f5e2cfe4c380c31b5c7db Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 17 Nov 2023 07:32:33 -0800 Subject: Support Rinho Telematics protocol --- src/main/java/org/traccar/protocol/TaipProtocolDecoder.java | 13 ++++++++----- .../java/org/traccar/protocol/TaipProtocolDecoderTest.java | 3 +++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java index 787ed1599..831910ab6 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -83,7 +83,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .or() .groupBegin() .number("(xx)") // input - .number("(xx)") // satellites + .number("xx") // satellites / outputs .number("(ddd)") // battery .number("(x{8})") // odometer .number("[01]") // gps power @@ -95,12 +95,14 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .number("[01]") // modem power .number("[0-5]") // gsm status .number("(dd)") // rssi + .groupBegin() .number("([-+]dddd)") // temperature 1 .number("xx") // seconds from last .number("([-+]dddd)") // temperature 2 .number("xx") // seconds from last .groupEnd("?") .groupEnd("?") + .groupEnd("?") .groupEnd() .any() .compile(); @@ -216,17 +218,18 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_HDOP, parser.nextInt()); } - if (parser.hasNext(4)) { + if (parser.hasNext(3)) { position.set(Position.KEY_INPUT, parser.nextHexInt(0)); - position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); position.set(Position.KEY_BATTERY, parser.nextInt(0)); position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0)); } - if (parser.hasNext(4)) { + if (parser.hasNext(3)) { valid = parser.nextInt() > 0; position.set(Position.KEY_PDOP, parser.nextInt()); position.set(Position.KEY_RSSI, parser.nextInt()); + } + if (parser.hasNext(2)) { position.set(Position.PREFIX_TEMP + 1, parser.nextInt() * 0.01); position.set(Position.PREFIX_TEMP + 2, parser.nextInt() * 0.01); } diff --git a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java index 2858248bd..3ad234b19 100644 --- a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class TaipProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TaipProtocolDecoder(null)); + verifyPosition(decoder, text( + ">RCQ00151123235718-2782354-06407582055121FF0013501CDCC6313011100001514;#0805;ID=SIA056;*15<")); + verifyNull(decoder, text( ">RTT151123153149-4330468-06503640000009300DF2101 04101203 000 00000000130000040414;ID=8803;#1ABD;*2B<")); -- cgit v1.2.3 From eacc6603272ba06ea257807415a966474e8cd020 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 17 Nov 2023 07:55:35 -0800 Subject: Support T711L sensor data --- .../java/org/traccar/protocol/MeitrackProtocolDecoder.java | 14 ++++++++++++++ .../org/traccar/protocol/MeitrackProtocolDecoderTest.java | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index ea3302c30..1235ca9fe 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -587,6 +587,20 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // alarm type buf.skipBytes(length - 2); break; + case 0xFE73: + buf.readUnsignedByte(); // version + position.set( + "tagName", + buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString()); + buf.skipBytes(6); // mac + position.set("tagBattery", buf.readUnsignedByte()); + position.set("tagTemp", buf.readUnsignedShortLE() / 256.0); + position.set("tagHumidity", buf.readUnsignedShortLE() / 256.0); + buf.readUnsignedShortLE(); // high temperature threshold + buf.readUnsignedShortLE(); // low temperature threshold + buf.readUnsignedShortLE(); // high humidity threshold + buf.readUnsignedShortLE(); // low humidity threshold + break; case 0xFEA8: for (int k = 1; k <= 3; k++) { if (buf.readUnsignedByte() > 0) { diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 91dcf0386..24dc9d18e 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "2424593136312c3836323039303035303031363139332c4343452c0000000001007f0017000705010607071714001500fe69601b00070800000971000a13000b19001605001acc0440230006029779570103eb5bcc06041ff0e8290c430100000d780400001c01000000030e0ccc010000922781abb90ca4fffe731e0109746e6873656e736f72ac233f6e219064051b753b00000000000000004b060101034c54452a42380d0a"), + "tagName", "tnhsensor"); + verifyAttribute(decoder, binary( "2424683136342C3836363334343035333039353238322C4343452C000000000100820018000505000600070B14001500080800000900000A00000B00001606001A0000402300FE90000006022E79570103E55CCC0604E1FDB32B0CC32C00000D58EB02001C01000000050E0CCC010000B627BF11000000004B1001010D475052532847534D2039303029FEA50601FFFFFF7FFFFEA80701010258023800FEB20501010000002A41360D0A"), "battery2Level", 88); -- cgit v1.2.3 From e5827b74db9432392b702f676fedb2aaacfd69f0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 17 Nov 2023 20:19:23 -0800 Subject: Fix TAIP ACK message --- .../org/traccar/protocol/TaipPrefixEncoder.java | 24 ++-------------------- .../java/org/traccar/protocol/TaipProtocol.java | 11 +++++++--- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java b/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java index 48419af2a..75fd447d0 100644 --- a/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java +++ b/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 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. @@ -15,40 +15,20 @@ */ package org.traccar.protocol; -import com.google.inject.Inject; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; -import org.traccar.Protocol; -import org.traccar.config.Config; -import org.traccar.config.Keys; import java.util.List; @ChannelHandler.Sharable public class TaipPrefixEncoder extends MessageToMessageEncoder { - private final Protocol protocol; - private Config config; - - public TaipPrefixEncoder(Protocol protocol) { - this.protocol = protocol; - } - - @Inject - public void setConfig(Config config) { - this.config = config; - } - @Override protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List out) { - if (config.getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(protocol.getName()))) { - out.add(Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[] {0x20, 0x20, 0x06, 0x00}), msg.retain())); - } else { - out.add(msg.retain()); - } + out.add(Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[] {0x20, 0x20, 0x06, 0x00}), msg.retain())); } } diff --git a/src/main/java/org/traccar/protocol/TaipProtocol.java b/src/main/java/org/traccar/protocol/TaipProtocol.java index 71ab485ca..f57bb296c 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocol.java +++ b/src/main/java/org/traccar/protocol/TaipProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -24,6 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import jakarta.inject.Inject; +import org.traccar.config.Keys; public class TaipProtocol extends BaseProtocol { @@ -33,7 +34,9 @@ public class TaipProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '<')); - pipeline.addLast(new TaipPrefixEncoder(TaipProtocol.this)); + if (config.getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(getName()))) { + pipeline.addLast(new TaipPrefixEncoder()); + } pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); @@ -42,7 +45,9 @@ public class TaipProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), true) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new TaipPrefixEncoder(TaipProtocol.this)); + if (config.getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(getName()))) { + pipeline.addLast(new TaipPrefixEncoder()); + } pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); -- cgit v1.2.3 From a9ba9a58a868309a9fc83cdb8710159c7786ca32 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Nov 2023 06:00:37 -0800 Subject: Skip old event notifications (fix #5217) --- src/main/java/org/traccar/config/Keys.java | 9 +++++++++ src/main/java/org/traccar/database/NotificationManager.java | 11 +++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index e7b07791f..3059c4f4b 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1167,6 +1167,15 @@ public final class Keys { "notificator.types", List.of(KeyType.CONFIG)); + /** + * If the event time is too old, we should not send notifications. This parameter is the threshold value in + * milliseconds. Default value is 15 minutes. + */ + public static final ConfigKey NOTIFICATOR_TIME_THRESHOLD = new LongConfigKey( + "notificator.timeThreshold", + List.of(KeyType.CONFIG), + 15 * 60 * 1000L); + /** * Traccar notification API key. */ diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 3a57788fb..03cfba418 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -58,6 +58,7 @@ public class NotificationManager { private final Geocoder geocoder; private final boolean geocodeOnRequest; + private final long timeThreshold; @Inject public NotificationManager( @@ -69,6 +70,7 @@ public class NotificationManager { this.notificatorManager = notificatorManager; this.geocoder = geocoder; geocodeOnRequest = config.getBoolean(Keys.GEOCODER_ON_REQUEST); + timeThreshold = config.getLong(Keys.NOTIFICATOR_TIME_THRESHOLD); } private void updateEvent(Event event, Position position) { @@ -78,6 +80,13 @@ public class NotificationManager { LOGGER.warn("Event save error", error); } + forwardEvent(event, position); + + if (System.currentTimeMillis() - event.getEventTime().getTime() > timeThreshold) { + LOGGER.info("Skipping notifications for old event"); + return; + } + var notifications = cacheManager.getDeviceObjects(event.getDeviceId(), Notification.class).stream() .filter(notification -> notification.getType().equals(event.getType())) .filter(notification -> { @@ -115,8 +124,6 @@ public class NotificationManager { }); }); } - - forwardEvent(event, position); } private void forwardEvent(Event event, Position position) { -- cgit v1.2.3 From b3463d2bb53dbb31d8b4aae58444fca353a3eca9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Nov 2023 06:06:46 -0800 Subject: Modify TAIP ACK order --- src/main/java/org/traccar/protocol/TaipProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java index 831910ab6..72090df8b 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -317,7 +317,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { if (messageIndex.startsWith("#IP")) { response = ">SAK;ID=" + uniqueId + ";" + messageIndex + "<"; } else { - response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*"; + response = ">ACK;" + messageIndex + ";ID=" + uniqueId + ";*"; response += String.format("%02X", Checksum.xor(response)) + "<"; } channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); -- cgit v1.2.3 From a7a5e0ad20d707e7f3527503ed124c6986118e87 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Nov 2023 06:10:11 -0800 Subject: Modify TAIP ACK order --- src/main/java/org/traccar/protocol/TaipProtocolDecoder.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java index 72090df8b..e953756b5 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -264,6 +264,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { String uniqueId = null; DeviceSession deviceSession = null; String messageIndex = null; + boolean indexFirst = true; if (attributes != null) { for (String attribute : attributes) { @@ -278,6 +279,9 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { if (deviceSession != null) { position.setDeviceId(deviceSession.getDeviceId()); } + if (messageIndex == null) { + indexFirst = false; + } break; case "io": position.set(Position.KEY_IGNITION, BitUtil.check(value.charAt(0) - '0', 0)); @@ -317,7 +321,11 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { if (messageIndex.startsWith("#IP")) { response = ">SAK;ID=" + uniqueId + ";" + messageIndex + "<"; } else { - response = ">ACK;" + messageIndex + ";ID=" + uniqueId + ";*"; + if (indexFirst) { + response = ">ACK;" + messageIndex + ";ID=" + uniqueId + ";*"; + } else { + response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*"; + } response += String.format("%02X", Checksum.xor(response)) + "<"; } channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); -- cgit v1.2.3 From 2d584e225ac56de1432a15243f981e294215fd10 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Nov 2023 06:44:16 -0800 Subject: Implement CR-GPS protocol support --- .../traccar/protocol/PortmanProtocolDecoder.java | 24 +++++++++++++++++----- .../protocol/PortmanProtocolDecoderTest.java | 3 +++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java b/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java index da9403313..716f2694b 100644 --- a/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2021 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. @@ -34,7 +34,11 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN_STANDARD = new PatternBuilder() + .groupBegin() .text("$PTMLA,") // header + .or() + .text("%%") // header + .groupEnd() .expression("([^,]+),") // id .expression("([ABCL]),") // validity .number("(dd)(dd)(dd)") // date (yymmdd) @@ -47,12 +51,19 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // course .number("(?:NA|C(-?d+)),") // temperature .number("(x{8}),") // status - .number("(?:NA|(d+)),") // card id + .groupBegin() + .text("NA") + .or() + .number("F(d+)") // fuel + .or() + .number("(d+)") // card id + .groupEnd(",") .number("(d+),") // event .number("(d+),") // satellites .number("(d+.d+),") // odometer - .number("(d+),") // rssi - .number("(?:G(d+)|[^,]*)") // fuel + .number("(d+)") // rssi + .number(",G(d+)").optional() // fuel + .any() .compile(); private Object decodeStandard(Channel channel, SocketAddress remoteAddress, String sentence) { @@ -79,6 +90,9 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, parser.next()); position.set(Position.KEY_STATUS, parser.nextHexLong()); + if (parser.hasNext()) { + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt() * 0.1); + } position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); int event = parser.nextInt(); @@ -159,7 +173,7 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { String sentence = (String) msg; - if (sentence.startsWith("$PTMLA")) { + if (sentence.startsWith("%%") || sentence.startsWith("$PTMLA")) { return decodeStandard(channel, remoteAddress, sentence); } else if (sentence.startsWith("$EXT")) { return decodeExtended(channel, remoteAddress, sentence); diff --git a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java index c5d57aa25..c4fbff7e9 100644 --- a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class PortmanProtocolDecoderTest extends ProtocolTest { var decoder = inject(new PortmanProtocolDecoder(null)); + verifyPosition(decoder, text( + "%%355854050074633,A,200612153351,N2543.0681W10009.2974,0,190,NA,C9830000,NA,108,8,2.66,16")); + verifyPosition(decoder, text( "$EXT,P0RTMANGRANT,A,210609201710,N0951.6879W08357.0129,0,0,NA,NA,11,25,174700.25,NA,01820000,108")); -- cgit v1.2.3 From a9029f335cd8a6493ee6b817e659e690bf0af614 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Nov 2023 07:36:33 -0800 Subject: Support GL521M light sensor --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 43 ++++++++++++++++++++++ .../protocol/Gl200TextProtocolDecoderTest.java | 4 ++ 2 files changed, 47 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index a4ace7a1c..290f35d83 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1282,6 +1282,46 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_LSA = new PatternBuilder() + .text("+RESP:GTLSA,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d,") // event state 1 + .number("d,") // event state 2 + .number("d+,") // number + .expression(PATTERN_LOCATION.pattern()) + .number("d+,") // bit error rate + .number("(d),") // light level + .number("(d+),") // battery level + .number("[01],") // mode selection + .number("[01]?,") // movement status + .number("(-?d+.d)?,") // temperature + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeLsa(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_LSA, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + decodeLocation(position, parser); + + position.set("lightLevel", parser.nextInt()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); + + decodeDeviceTime(position, parser); + + return position; + } + private static final Pattern PATTERN = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GT...,") .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version @@ -1536,6 +1576,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { case "BID": result = decodeBid(channel, remoteAddress, sentence); break; + case "LSA": + result = decodeLsa(channel, remoteAddress, sentence); + break; default: result = decodeOther(channel, remoteAddress, sentence, type); break; diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index a23b87fe5..0a0d27e3e 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+RESP:GTLSA,C50204,866356062524268,,1,0,1,0,0.0,0,123.3,4.730544,51.620446,20231116021001,0204,0008,0D0C,309C,18,1,7,96,0,,,20231116080602,0040$"), + "lightLevel", 7); + verifyAttribute(decoder, buffer( "+RESP:GTFRI,423037,866884047716519,GT501,0,1,1,5,12,0.1,0,46.8,-95.559173,30.109955,20231110185836,6,0e36c9916485,-50,,,,e831cd5eb79d,-73,,,,ccf4110c4bd5,-79,,,,acdb48973168,-79,,,,80ab4dc323c4,-82,,,,ec8eb5cfa1c6,-89,,,,310,10,711D,81ECF0F,00,,93,20231110185839,0005$"), Position.KEY_BATTERY_LEVEL, 93); -- cgit v1.2.3 From 204ece58b93f3582d6b03d818c81b42adb603b95 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Nov 2023 20:33:50 -0800 Subject: Replace with a real sample --- src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java index c4fbff7e9..b86d7340e 100644 --- a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java @@ -11,7 +11,7 @@ public class PortmanProtocolDecoderTest extends ProtocolTest { var decoder = inject(new PortmanProtocolDecoder(null)); verifyPosition(decoder, text( - "%%355854050074633,A,200612153351,N2543.0681W10009.2974,0,190,NA,C9830000,NA,108,8,2.66,16")); + "%%863922034547720,A,231119031316,N3640.4542E11707.5992,000,000,NA,95000000,NA,254,24,1.00,24")); verifyPosition(decoder, text( "$EXT,P0RTMANGRANT,A,210609201710,N0951.6879W08357.0129,0,0,NA,NA,11,25,174700.25,NA,01820000,108")); -- cgit v1.2.3 From 10546bfafe1f994eb44080d0d9b10bbd30f6739e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 19 Nov 2023 15:01:42 -0800 Subject: Update java dependencies --- build.gradle | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index 75fe792b0..45e35c049 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id "java" id "checkstyle" - id "com.google.protobuf" version "0.9.3" + id "com.google.protobuf" version "0.9.4" id "org.kordamp.gradle.project-enforcer" version "0.13.0" } @@ -27,12 +27,12 @@ enforce { ext { guiceVersion = "7.0.0" - jettyVersion = "11.0.15" + jettyVersion = "11.0.18" jerseyVersion = "3.1.3" jacksonVersion = "2.15.2" // same version as jersey-media-json-jackson dependency protobufVersion = "3.24.0" jxlsVersion = "2.13.0" - junitVersion = "5.10.0" + junitVersion = "5.10.1" } protobuf { @@ -43,14 +43,14 @@ protobuf { dependencies { implementation "commons-codec:commons-codec:1.16.0" - implementation "com.h2database:h2:2.2.220" - implementation "com.mysql:mysql-connector-j:8.1.0" - implementation "org.mariadb.jdbc:mariadb-java-client:3.1.4" + implementation "com.h2database:h2:2.2.224" + implementation "com.mysql:mysql-connector-j:8.2.0" + implementation "org.mariadb.jdbc:mariadb-java-client:3.3.0" implementation "org.postgresql:postgresql:42.6.0" - implementation "com.microsoft.sqlserver:mssql-jdbc:12.4.0.jre11" - implementation "com.zaxxer:HikariCP:5.0.1" - implementation "io.netty:netty-all:4.1.96.Final" - implementation "org.slf4j:slf4j-jdk14:2.0.7" + implementation "com.microsoft.sqlserver:mssql-jdbc:12.4.2.jre11" + implementation "com.zaxxer:HikariCP:5.1.0" + implementation "io.netty:netty-all:4.1.101.Final" + implementation "org.slf4j:slf4j-jdk14:2.0.9" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" @@ -69,31 +69,31 @@ dependencies { implementation "org.glassfish.hk2:guice-bridge:3.0.4" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.23.1" + implementation "org.liquibase:liquibase-core:4.25.0" implementation "org.apache.commons:commons-jexl3:3.3" implementation "org.jxls:jxls:$jxlsVersion" implementation "org.jxls:jxls-poi:$jxlsVersion" implementation "org.apache.velocity:velocity-engine-core:2.3" implementation "org.apache.velocity.tools:velocity-tools-generic:3.1" implementation "org.apache.commons:commons-collections4:4.4" - implementation "org.mnode.ical4j:ical4j:3.2.12" + implementation "org.mnode.ical4j:ical4j:3.2.14" implementation "org.locationtech.spatial4j:spatial4j:0.8" implementation "org.locationtech.jts:jts-core:1.19.0" implementation "net.java.dev.jna:jna-platform:5.13.0" - implementation "com.github.jnr:jnr-posix:3.1.17" + implementation "com.github.jnr:jnr-posix:3.1.18" implementation "com.google.protobuf:protobuf-java:$protobufVersion" - implementation "javax.activation:activation:1.1.1" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.532" - implementation "org.apache.kafka:kafka-clients:3.5.1" - implementation "com.hivemq:hivemq-mqtt-client:1.3.1" - implementation "redis.clients:jedis:4.4.3" + implementation "javax.activation:activation:1.1.1" // TODO + implementation "com.amazonaws:aws-java-sdk-sns:1.12.592" + implementation "org.apache.kafka:kafka-clients:3.6.0" + implementation "com.hivemq:hivemq-mqtt-client:1.3.3" + implementation "redis.clients:jedis:5.0.2" implementation "com.google.firebase:firebase-admin:9.2.0" - implementation "com.nimbusds:oauth2-oidc-sdk:10.13.2" - implementation "com.rabbitmq:amqp-client:5.18.0" - implementation "com.warrenstrange:googleauth:1.2.0" + implementation "com.nimbusds:oauth2-oidc-sdk:11.6" + implementation "com.rabbitmq:amqp-client:5.20.0" + implementation "com.warrenstrange:googleauth:1.5.0" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:5.4.0" + testImplementation "org.mockito:mockito-core:5.7.0" } test { -- cgit v1.2.3 From c4bc919e3490dfc4d1d20d6b41e48003d1400073 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Nov 2023 10:40:58 -0800 Subject: Improve Queclink basic pattern --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- .../java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 290f35d83..5ee3761dd 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1398,7 +1398,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_BASIC = new PatternBuilder() .text("+").expression("(?:RESP|BUFF)").text(":") .expression("GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version + .expression("[^,]+,").optional() // protocol version .number("(d{15}|x{14}),") // imei .any() .text(",") diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 0a0d27e3e..037c8f75a 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,15 +11,14 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); - verifyAttribute(decoder, buffer( - "+RESP:GTLSA,C50204,866356062524268,,1,0,1,0,0.0,0,123.3,4.730544,51.620446,20231116021001,0204,0008,0D0C,309C,18,1,7,96,0,,,20231116080602,0040$"), - "lightLevel", 7); + verifyPosition(decoder, buffer( + "+BUFF:GTFRI,8020040200,866314060249032,,12194,10,1,3,0.0,0,20.1,-71.596533,-33.524718,20230926200338,0730,0001,772A,052B253E,02,0,0.0,,,,,0,420000,,,,20230926200340,1549$")); verifyAttribute(decoder, buffer( "+RESP:GTFRI,423037,866884047716519,GT501,0,1,1,5,12,0.1,0,46.8,-95.559173,30.109955,20231110185836,6,0e36c9916485,-50,,,,e831cd5eb79d,-73,,,,ccf4110c4bd5,-79,,,,acdb48973168,-79,,,,80ab4dc323c4,-82,,,,ec8eb5cfa1c6,-89,,,,310,10,711D,81ECF0F,00,,93,20231110185839,0005$"), Position.KEY_BATTERY_LEVEL, 93); - verifyNull(decoder, buffer( + verifyPosition(decoder, buffer( "+RESP:GTFRI,8020040200,866314060109269,,,10,1,1,0.0,0,9.0,-71.596601,-33.524595,20230722145338,0730,0001,772A,052B253E,00,0.0,,,,,100,210100,,,,20230722145341,0F4C$")); verifyAttributes(decoder, buffer( -- cgit v1.2.3 From 05ec7e73132369518b5122b2aecbf0f1a65c437f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Nov 2023 14:09:04 -0800 Subject: Downgrade liquibase version --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 45e35c049..92aad7dba 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ dependencies { implementation "org.glassfish.hk2:guice-bridge:3.0.4" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.25.0" + implementation "org.liquibase:liquibase-core:4.24.0" // upgrade had issues implementation "org.apache.commons:commons-jexl3:3.3" implementation "org.jxls:jxls:$jxlsVersion" implementation "org.jxls:jxls-poi:$jxlsVersion" @@ -82,7 +82,6 @@ dependencies { implementation "net.java.dev.jna:jna-platform:5.13.0" implementation "com.github.jnr:jnr-posix:3.1.18" implementation "com.google.protobuf:protobuf-java:$protobufVersion" - implementation "javax.activation:activation:1.1.1" // TODO implementation "com.amazonaws:aws-java-sdk-sns:1.12.592" implementation "org.apache.kafka:kafka-clients:3.6.0" implementation "com.hivemq:hivemq-mqtt-client:1.3.3" -- cgit v1.2.3 From 830aeed832e99a455601646fc0057584a203fdfe Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Nov 2023 14:10:16 -0800 Subject: Update version numbers --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 92aad7dba..987c60cc1 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.9", + "Implementation-Version": "5.10", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 9d9fbc73c..23daf6e13 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.9 +AppVersion=5.10 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index ae8c447cc..982e1bff1 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.9", + "version": "5.10", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From d02ca68f6a73dbf35f734fc8e4be85ba8563e839 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 Nov 2023 14:59:33 -0800 Subject: Downgrade liquibase version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 987c60cc1..a51ebaff0 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ dependencies { implementation "org.glassfish.hk2:guice-bridge:3.0.4" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.24.0" // upgrade had issues + implementation "org.liquibase:liquibase-core:4.23.2" // upgrade has issues implementation "org.apache.commons:commons-jexl3:3.3" implementation "org.jxls:jxls:$jxlsVersion" implementation "org.jxls:jxls-poi:$jxlsVersion" -- cgit v1.2.3 From 01a4721538ef5ab75b708d2e0084e0f489451630 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Nov 2023 06:48:25 -0800 Subject: Fix override filter length issue --- src/main/java/org/traccar/web/OverrideFilter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java index 917fb74cc..9780c9ede 100644 --- a/src/main/java/org/traccar/web/OverrideFilter.java +++ b/src/main/java/org/traccar/web/OverrideFilter.java @@ -75,8 +75,9 @@ public class OverrideFilter implements Filter { .replace("${description}", description) .replace("${colorPrimary}", colorPrimary); - response.setContentLength(alteredContent.length()); - response.getOutputStream().write(alteredContent.getBytes()); + byte[] data = alteredContent.getBytes(); + response.setContentLength(data.length); + response.getOutputStream().write(data); } else { response.getOutputStream().write(bytes); -- cgit v1.2.3 From fabd96bbb09ce81aac16357b22e8529bd545bd1b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Nov 2023 07:32:20 -0800 Subject: Update submodule --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 9bd75b29e..dc46059f6 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 9bd75b29e3654e0854e3ae35741609dd24ceb218 +Subproject commit dc46059f6bfeedca04333c2839872055db066dc6 -- cgit v1.2.3 From 008a304d8e7c7834af6f8f699089b4c1775ad4f1 Mon Sep 17 00:00:00 2001 From: Nikutrax <112165998+Nikutrax@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:39:38 +0100 Subject: Update FifotrackProtocolDecoder.java Add Alarm Power ON Add Alarm Power OFF --- src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index 95b7e2733..59019830f 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -194,6 +194,10 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { case 40: case 41: return Position.ALARM_TEMPERATURE; + case 53: + return Position.ALARM_POWER_ON; + case 54: + return Position.ALARM_POWER_OFF; default: return null; } -- cgit v1.2.3 From b611af130271182c8e9de924a33f172ee4431a93 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Nov 2023 06:38:04 -0800 Subject: Fix Mictrack MT710 wifi decoding --- src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java | 4 +++- src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index 5ba053df3..2e7cdde4e 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -210,7 +210,9 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { parser = new Parser(PATTERN_WIFI, message); if (parser.matches()) { - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); + if (parser.hasNext()) { + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); + } Network network = new Network(); if (parser.hasNext(4)) { diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java index 63aa3ebc0..cdfae465c 100644 --- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tlt2hProtocolDecoder(null)); + verifyPositions(decoder, false, text( + "#862255061983166#MT700NW#0000#TOWED#1\r\n", + "#4502$WIFI,051550.00,A,-50,7683C2CBC0B0,-51,7683C29BC0B0,-51,7683C2BBC0B0,-51,7483C2DBC0B0,-51,7683C2ABC0B0,221123*78\r\n")); + verifyPositions(decoder, false, text( "#862255061825896#MT710#0000#TOWED#1\r\n", "#39#$WIFI,015259.00,A,-47,7483C2DBC0B0,-48,7683C2ABC0B0,-48,7683C29BC0B0,-48,7683C2CBC0B0,-48,7683C2BBC0B0,151123*74\r\n")); -- cgit v1.2.3 From e40b26908c32560c06c9fe47e9ab42f15054c586 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Nov 2023 13:30:04 -0800 Subject: Support null timezone --- src/main/java/org/traccar/BaseProtocolDecoder.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 69ca0ccc6..97762e8ca 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -125,12 +125,13 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { } protected TimeZone getTimeZone(long deviceId, String defaultTimeZone) { - TimeZone result = TimeZone.getTimeZone(defaultTimeZone); String timeZoneName = AttributeUtil.lookup(cacheManager, Keys.DECODER_TIMEZONE, deviceId); if (timeZoneName != null) { - result = TimeZone.getTimeZone(timeZoneName); + return TimeZone.getTimeZone(timeZoneName); + } else if (defaultTimeZone != null) { + return TimeZone.getTimeZone(defaultTimeZone); } - return result; + return null; } public DeviceSession getDeviceSession(Channel channel, SocketAddress remoteAddress, String... uniqueIds) { -- cgit v1.2.3 From c4d2cf73f5a66759f7940ba4c11ec63976c05367 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Nov 2023 13:37:36 -0800 Subject: Improve GT06 timezone handling --- .../org/traccar/protocol/Gt06ProtocolDecoder.java | 31 +++++++++------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index cf7cd12d3..7ee47dd86 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -480,28 +480,21 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShort(); // type deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null && !deviceSession.contains(DeviceSession.KEY_TIMEZONE)) { - deviceSession.set(DeviceSession.KEY_TIMEZONE, getTimeZone(deviceSession.getDeviceId())); - } - - if (dataLength > 10) { - int extensionBits = buf.readUnsignedShort(); - int hours = (extensionBits >> 4) / 100; - int minutes = (extensionBits >> 4) % 100; - int offset = (hours * 60 + minutes) * 60; - if ((extensionBits & 0x8) != 0) { - offset = -offset; - } - if (deviceSession != null) { - TimeZone timeZone = deviceSession.get(DeviceSession.KEY_TIMEZONE); - if (timeZone.getRawOffset() == 0) { - timeZone.setRawOffset(offset * 1000); - deviceSession.set(DeviceSession.KEY_TIMEZONE, timeZone); + if (deviceSession != null) { + TimeZone timeZone = getTimeZone(deviceSession.getDeviceId(), null); + if (timeZone == null && dataLength > 10) { + int extensionBits = buf.readUnsignedShort(); + int hours = (extensionBits >> 4) / 100; + int minutes = (extensionBits >> 4) % 100; + int offset = (hours * 60 + minutes) * 60; + if ((extensionBits & 0x8) != 0) { + offset = -offset; } + timeZone = TimeZone.getTimeZone("UTC"); + timeZone.setRawOffset(offset * 1000); } - } + deviceSession.set(DeviceSession.KEY_TIMEZONE, timeZone); - if (deviceSession != null) { sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); } -- cgit v1.2.3 From 41b5577dd8574309104c880191a35ba3bca600d4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Nov 2023 14:06:02 -0800 Subject: Fix RST ignition value --- .../org/traccar/protocol/RstProtocolDecoder.java | 23 ++++++++++++---------- .../traccar/protocol/RstProtocolDecoderTest.java | 4 ++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java index fcc96fbf1..d53675b7f 100644 --- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -42,7 +42,7 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { .expression("(.{5});") // firmware .number("(d{9});") // serial number .number("(d+);") // index - .number("(d+);") // type + .number("d+;") // type .groupBegin() .number("(dd)-(dd)-(dddd) ") // event date .number("(dd):(dd):(dd);") // event time @@ -87,7 +87,6 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { String firmware = parser.next(); String serial = parser.next(); int index = parser.nextInt(); - int type = parser.nextInt(); if (channel != null) { String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";6;FIM;"; @@ -115,9 +114,16 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_SATELLITES, parser.nextInt()); position.set(Position.KEY_HDOP, parser.nextInt()); - position.set(Position.PREFIX_IN + 1, parser.nextHexInt()); - position.set(Position.PREFIX_IN + 2, parser.nextHexInt()); - position.set(Position.PREFIX_IN + 3, parser.nextHexInt()); + + int inputs1 = parser.nextHexInt(); + int inputs2 = parser.nextHexInt(); + int inputs3 = parser.nextHexInt(); + position.set(Position.PREFIX_IN + 1, inputs1); + position.set(Position.PREFIX_IN + 2, inputs2); + position.set(Position.PREFIX_IN + 3, inputs3); + + position.set(Position.KEY_IGNITION, BitUtil.check(inputs2, 7)); + position.set(Position.PREFIX_OUT + 1, parser.nextHexInt()); position.set(Position.PREFIX_OUT + 2, parser.nextHexInt()); position.set(Position.KEY_POWER, parser.nextDouble()); @@ -125,10 +131,7 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, parser.nextInt()); position.set(Position.KEY_RSSI, parser.nextInt()); position.set(Position.PREFIX_TEMP + 1, (int) parser.nextHexInt().byteValue()); - - int status = (parser.nextHexInt() << 8) + parser.nextHexInt(); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 7)); - position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_STATUS, (parser.nextHexInt() << 8) + parser.nextHexInt()); return position; diff --git a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java index 13095765b..0e8aefe51 100644 --- a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java @@ -14,6 +14,10 @@ public class RstProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, text( "RST;A;RST-MINIv2;V7.04;008051261;124;29;04-04-2021 17:27:26;04-04-2021 17:27:26;-1.280811;-47.931755;7353;79;1;14;7315;26;10;0;1855;0;0;0;0;5;5;-1.280821;-47.931747;04-04-2021 17:52:23;6;-1.280863;-47.931770;04-04-2021 18:12:19;5;-1.280844;-47.931763;04-04-2021 17:28:02;5;-1.280900;-47.931770;04-04-2021 19:04:27;4;-1.280843;-47.931747;04-04-2021 18:21:45;04-04-2021 19:29:59;04-04-2021 19:29:59;-1.280770;-47.931595;1;15;0;0;0;0;FIM;")); + verifyAttribute(decoder, text( + "RST;A;RST-MINI-4Gv3;V9.10;009521405;13;1;21-11-2023 20:04:18;21-11-2023 20:04:18;-12.923627;-38.388287;1;165;29;1;5;2;00;B0;00;1A;02;11.89;3.90;73;31;FE;0000;01;40;00800061;0;184;2;4;4;6;434.0000;2;0;-49;1815;37391;724;255;263;00000000;FIM;"), + Position.KEY_IGNITION, true); + verifyPosition(decoder, text( "RST;L;RST-MINIv2;V7.02;008068078;61;1;27-01-2020 21:36:33;27-01-2020 21:36:33;-16.696159;-49.284275;0;67;786;1;15;0;00;B0;00;19;06;12.42;4.16;79;20;FE;0000;01;E0;00800020;0;467;FIM;")); -- cgit v1.2.3 From 25c5e09b02ae9e498562f3fe9a80bd6d7463a11b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 25 Nov 2023 08:06:25 -0800 Subject: Support JT705A additional data --- .../traccar/protocol/HuabaoProtocolDecoder.java | 43 ++++++++++++++++++++-- .../org/traccar/protocol/Jt600ProtocolDecoder.java | 12 ++---- .../protocol/HuabaoProtocolDecoderTest.java | 10 +++++ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 6e8373373..881209120 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -770,12 +770,15 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int battery = buf.readUnsignedByte(); if (battery <= 100) { position.set(Position.KEY_BATTERY_LEVEL, battery); - } else if (battery == 0xAA) { + } else if (battery == 0xAA || battery == 0xAB) { position.set(Position.KEY_CHARGE, true); } - position.setNetwork(new Network(CellTower.fromCidLac( - getConfig(), buf.readUnsignedInt(), buf.readUnsignedShort()))); + long cid = buf.readUnsignedInt(); + int lac = buf.readUnsignedShort(); + if (cid > 0 && lac > 0) { + position.setNetwork(new Network(CellTower.fromCidLac(getConfig(), cid, lac))); + } int product = buf.readUnsignedByte(); int status = buf.readUnsignedShort(); @@ -787,6 +790,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } } else if (product == 3) { position.set(Position.KEY_BLOCKED, BitUtil.check(status, 5)); + if (BitUtil.check(alarm, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } if (BitUtil.check(alarm, 1)) { position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); } @@ -796,6 +802,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(alarm, 3)) { position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); } + if (BitUtil.check(alarm, 5)) { + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER); + } + if (BitUtil.check(alarm, 6)) { + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); + } } position.set(Position.KEY_STATUS, status); @@ -807,6 +819,28 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x02: position.setAltitude(buf.readShort()); break; + case 0x10: + position.set("wakeSource", buf.readUnsignedByte()); + break; + case 0x0A: + if (length == 3) { + buf.readUnsignedShort(); // mcc + buf.readUnsignedByte(); // mnc + } else { + buf.skipBytes(length); + } + break; + case 0x0B: + position.set("lockCommand", buf.readUnsignedByte()); + if (length >= 5 && length <= 6) { + position.set("lockCard", buf.readUnsignedInt()); + } else if (length >= 7) { + position.set("lockPassword", buf.readCharSequence(6, StandardCharsets.US_ASCII).toString()); + } + if (length % 2 == 0) { + position.set("unlockResult", buf.readUnsignedByte()); + } + break; case 0x0C: int x = buf.readUnsignedShort(); if (x > 0x8000) { @@ -822,6 +856,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } position.set("tilt", String.format("[%d,%d,%d]", x, y, z)); break; + case 0xFC: + position.set(Position.KEY_GEOFENCE, buf.readUnsignedByte()); + break; default: buf.skipBytes(length); break; diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java index 1b6d471b4..eca7e2d11 100644 --- a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java @@ -105,15 +105,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { double longitude = convertCoordinate(BcdUtil.readInteger(buf, 9)); byte flags = buf.readByte(); - position.setValid((flags & 0x1) == 0x1); - if ((flags & 0x2) == 0) { - latitude = -latitude; - } - position.setLatitude(latitude); - if ((flags & 0x4) == 0) { - longitude = -longitude; - } - position.setLongitude(longitude); + position.setValid(BitUtil.check(flags, 0)); + position.setLatitude(BitUtil.check(flags, 1) ? latitude : -latitude); + position.setLongitude(BitUtil.check(flags, 2) ? longitude : -longitude); position.setSpeed(BcdUtil.readInteger(buf, 2)); position.setCourse(buf.readUnsignedByte() * 2.0); diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 22c34c7ac..164635109 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -11,6 +11,16 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new HuabaoProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "7e55018c418560090010174701022106242122348476113550490700001c06000000074e0000000000000308100000100102020200000a030000000b0803363839363037650c0600000001000afa7e"), + "unlockResult", 0x65); + + verifyPosition(decoder, binary( + "7e55018c378580120300032a06052117594022348474113550560705981e0400000002370ac30c0c28660308000000100101020200000a0301cc000c0600a2ffa7ff5e1b7e")); + + verifyPosition(decoder, binary( + "7e55028c37850011000200c008052106305122348621113550170700001e080000000aaa0000000000000300000000100100020200140a030000000c06003bffa8ffc3c77e")); + verifyAttribute(decoder, binary( "7E020000C2000000001862003F0000000400108042015A322206C869480017007B012E230918081550661D01CC1A0000099DC25727B0130000099DC26B27B00100000C40F89427B0711438393836303436393130323139303037383135336A0114503FF8AF05826BC8CA24E124F732B7C780C5484D6318C0A840412262D4BCEC26CA0234CCB85455D5114F12B650FA841FBEC0B03C67A21F501CAE6C384595028DA76B010060110065000012345678903930303137333833630B0012345678900E5C3080006804000003D46902016F6D7E"), Position.KEY_DRIVER_UNIQUE_ID, "\u00909001738"); -- cgit v1.2.3 From a59a6d19f575d8b593085ce19458c8fff18a6360 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 25 Nov 2023 14:19:23 -0800 Subject: Add device sharing (fix #3789, fix #4936, fix #5025) --- schema/changelog-5.11.xml | 17 ++++++ schema/changelog-master.xml | 1 + .../org/traccar/api/resource/DeviceResource.java | 37 +++++++++++++ src/main/java/org/traccar/model/User.java | 10 ++++ .../java/org/traccar/schedule/ScheduleManager.java | 1 + .../org/traccar/schedule/TaskDeleteTemporary.java | 61 ++++++++++++++++++++++ .../java/org/traccar/schedule/TaskReports.java | 2 +- 7 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 schema/changelog-5.11.xml create mode 100644 src/main/java/org/traccar/schedule/TaskDeleteTemporary.java diff --git a/schema/changelog-5.11.xml b/schema/changelog-5.11.xml new file mode 100644 index 000000000..e59df9249 --- /dev/null +++ b/schema/changelog-5.11.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index 183b3fd93..559d90923 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -41,5 +41,6 @@ + diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 61a70bac0..ebc40a9b1 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -15,12 +15,15 @@ */ package org.traccar.api.resource; +import jakarta.ws.rs.FormParam; import org.traccar.api.BaseObjectResource; +import org.traccar.api.signature.TokenManager; import org.traccar.broadcast.BroadcastService; import org.traccar.database.MediaManager; import org.traccar.helper.LogAction; import org.traccar.model.Device; import org.traccar.model.DeviceAccumulators; +import org.traccar.model.Permission; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.session.ConnectionManager; @@ -46,7 +49,9 @@ import jakarta.ws.rs.core.Response; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.security.GeneralSecurityException; import java.util.Collection; +import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -67,6 +72,9 @@ public class DeviceResource extends BaseObjectResource { @Inject private MediaManager mediaManager; + @Inject + private TokenManager tokenManager; + public DeviceResource() { super(Device.class); } @@ -183,4 +191,33 @@ public class DeviceResource extends BaseObjectResource { return Response.status(Response.Status.NOT_FOUND).build(); } + @Path("share") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @POST + public String shareDevice( + @FormParam("deviceId") long deviceId, + @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { + + User user = permissionsService.getUser(getUserId()); + + Device device = storage.getObject(Device.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("id", deviceId), + new Condition.Permission(User.class, user.getId(), Device.class)))); + + User share = new User(); + share.setName(device.getName()); + share.setEmail(user.getEmail() + ":" + device.getUniqueId()); + share.setExpirationTime(expiration); + share.setTemporary(true); + share.setReadonly(true); + + share.setId(storage.addObject(share, new Request(new Columns.Exclude("id")))); + + storage.addPermission(new Permission(User.class, share.getId(), Device.class, deviceId)); + + return tokenManager.generateToken(share.getId(), expiration); + } + } diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 757064ba2..8cfee0f48 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -261,6 +261,16 @@ public class User extends ExtendedModel implements UserRestrictions, Disableable this.totpKey = totpKey; } + private boolean temporary; + + public boolean getTemporary() { + return temporary; + } + + public void setTemporary(boolean temporary) { + this.temporary = temporary; + } + @QueryIgnore public String getPassword() { return null; diff --git a/src/main/java/org/traccar/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java index 07cdb1fe1..38e8f281c 100644 --- a/src/main/java/org/traccar/schedule/ScheduleManager.java +++ b/src/main/java/org/traccar/schedule/ScheduleManager.java @@ -39,6 +39,7 @@ public class ScheduleManager implements LifecycleObject { public void start() { executor = Executors.newSingleThreadScheduledExecutor(); var tasks = List.of( + TaskDeleteTemporary.class, TaskReports.class, TaskDeviceInactivityCheck.class, TaskWebSocketKeepalive.class, diff --git a/src/main/java/org/traccar/schedule/TaskDeleteTemporary.java b/src/main/java/org/traccar/schedule/TaskDeleteTemporary.java new file mode 100644 index 000000000..0cead59fb --- /dev/null +++ b/src/main/java/org/traccar/schedule/TaskDeleteTemporary.java @@ -0,0 +1,61 @@ +/* + * 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.schedule; + +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import java.util.Date; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class TaskDeleteTemporary implements ScheduleTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(TaskDeleteTemporary.class); + + private static final long CHECK_PERIOD_HOURS = 1; + + private final Storage storage; + + @Inject + public TaskDeleteTemporary(Storage storage) { + this.storage = storage; + } + + @Override + public void schedule(ScheduledExecutorService executor) { + executor.scheduleAtFixedRate(this, CHECK_PERIOD_HOURS, CHECK_PERIOD_HOURS, TimeUnit.HOURS); + } + + @Override + public void run() { + try { + storage.removeObject(User.class, new Request( + new Condition.And( + new Condition.Equals("temporary", true), + new Condition.Compare("expirationTime", "<", "time", new Date())))); + } catch (StorageException e) { + LOGGER.warn("Failed to delete temporary users", e); + } + } + +} diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index 30f20f437..e0fa6f8d6 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.java @@ -51,7 +51,7 @@ public class TaskReports implements ScheduleTask { private static final Logger LOGGER = LoggerFactory.getLogger(TaskReports.class); - private static final long CHECK_PERIOD_MINUTES = 1; + private static final long CHECK_PERIOD_MINUTES = 15; private final Storage storage; private final Injector injector; -- cgit v1.2.3 From 08cb38a2126e91ccde44e9f91d2ad1f149c7e6b5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Nov 2023 08:03:53 -0800 Subject: Add login result class --- .../org/traccar/api/resource/SessionResource.java | 6 +++--- .../java/org/traccar/api/security/LoginResult.java | 25 ++++++++++++++++++++++ .../org/traccar/api/security/LoginService.java | 18 ++++++++-------- .../api/security/SecurityRequestFilter.java | 7 +++--- .../java/org/traccar/database/OpenIdProvider.java | 3 ++- 5 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/traccar/api/security/LoginResult.java diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 90f0ceade..3e80e0020 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -82,7 +82,7 @@ public class SessionResource extends BaseResource { public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException { if (token != null) { - User user = loginService.login(token); + User user = loginService.login(token).getUser(); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); @@ -109,7 +109,7 @@ public class SessionResource extends BaseResource { } } if (email != null && password != null) { - User user = loginService.login(email, password, null); + User user = loginService.login(email, password, null).getUser(); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); @@ -148,7 +148,7 @@ public class SessionResource extends BaseResource { @FormParam("code") Integer code) throws StorageException { User user; try { - user = loginService.login(email, password, code); + user = loginService.login(email, password, code).getUser(); } catch (CodeRequiredException e) { Response response = Response .status(Response.Status.UNAUTHORIZED) diff --git a/src/main/java/org/traccar/api/security/LoginResult.java b/src/main/java/org/traccar/api/security/LoginResult.java new file mode 100644 index 000000000..66c35bbed --- /dev/null +++ b/src/main/java/org/traccar/api/security/LoginResult.java @@ -0,0 +1,25 @@ +package org.traccar.api.security; + +import org.traccar.model.User; + +import java.util.Date; + +public class LoginResult { + + private final User user; + private final Date expiration; + + public LoginResult(User user) { + this.user = user; + expiration = null; + } + + public User getUser() { + return user; + } + + public Date getExpiration() { + return expiration; + } + +} diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 829f5d2fa..6246d2494 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -58,9 +58,9 @@ public class LoginService { forceOpenId = config.getBoolean(Keys.OPENID_FORCE); } - public User login(String token) throws StorageException, GeneralSecurityException, IOException { + public LoginResult login(String token) throws StorageException, GeneralSecurityException, IOException { if (serviceAccountToken != null && serviceAccountToken.equals(token)) { - return new ServiceAccountUser(); + return new LoginResult(new ServiceAccountUser()); } long userId = tokenManager.verifyToken(token); User user = storage.getObject(User.class, new Request( @@ -68,10 +68,10 @@ public class LoginService { if (user != null) { checkUserEnabled(user); } - return user; + return new LoginResult(user); } - public User login(String email, String password, Integer code) throws StorageException { + public LoginResult login(String email, String password, Integer code) throws StorageException { if (forceOpenId) { return null; } @@ -87,20 +87,20 @@ public class LoginService { || !forceLdap && user.isPasswordValid(password)) { checkUserCode(user, code); checkUserEnabled(user); - return user; + return new LoginResult(user); } } else { if (ldapProvider != null && ldapProvider.login(email, password)) { user = ldapProvider.getUser(email); user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); checkUserEnabled(user); - return user; + return new LoginResult(user); } } return null; } - public User login(String email, String name, boolean administrator) throws StorageException { + public LoginResult login(String email, String name, boolean administrator) throws StorageException { User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Equals("email", email))); @@ -115,7 +115,7 @@ public class LoginService { user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); } checkUserEnabled(user); - return user; + return new LoginResult(user); } private void checkUserEnabled(User user) throws SecurityException { diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index cb523177e..e308024da 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -82,13 +82,14 @@ public class SecurityRequestFilter implements ContainerRequestFilter { if (authHeader != null) { try { - User user; + LoginResult loginResult; if (authHeader.startsWith("Bearer ")) { - user = loginService.login(authHeader.substring(7)); + loginResult = loginService.login(authHeader.substring(7)); } else { String[] auth = decodeBasicAuth(authHeader); - user = loginService.login(auth[0], auth[1], null); + loginResult = loginService.login(auth[0], auth[1], null); } + User user = loginResult.getUser(); if (user != null) { statisticsManager.registerRequest(user.getId()); securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java index 1f5a2f481..93297f7ab 100644 --- a/src/main/java/org/traccar/database/OpenIdProvider.java +++ b/src/main/java/org/traccar/database/OpenIdProvider.java @@ -189,7 +189,8 @@ public class OpenIdProvider { throw new GeneralSecurityException("Your OpenID Groups do not permit access to Traccar."); } - User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), administrator); + User user = loginService.login( + userInfo.getEmailAddress(), userInfo.getName(), administrator).getUser(); request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); -- cgit v1.2.3 From acdc451e3e2ab94f548f078c4bd49985b3c2f01d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Nov 2023 08:07:52 -0800 Subject: Set expiration from token --- .../org/traccar/api/resource/PasswordResource.java | 2 +- .../java/org/traccar/api/security/LoginResult.java | 6 +++++- .../java/org/traccar/api/security/LoginService.java | 6 +++--- .../java/org/traccar/api/signature/TokenManager.java | 20 ++++++++++++++------ 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 029e63a0c..22b3f0cd3 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -75,7 +75,7 @@ public class PasswordResource extends BaseResource { @FormParam("token") String token, @FormParam("password") String password) throws StorageException, GeneralSecurityException, IOException { - long userId = tokenManager.verifyToken(token); + long userId = tokenManager.verifyToken(token).getUserId(); User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Equals("id", userId))); if (user != null) { diff --git a/src/main/java/org/traccar/api/security/LoginResult.java b/src/main/java/org/traccar/api/security/LoginResult.java index 66c35bbed..1fccc36d1 100644 --- a/src/main/java/org/traccar/api/security/LoginResult.java +++ b/src/main/java/org/traccar/api/security/LoginResult.java @@ -10,8 +10,12 @@ public class LoginResult { private final Date expiration; public LoginResult(User user) { + this(user, null); + } + + public LoginResult(User user, Date expiration) { this.user = user; - expiration = null; + this.expiration = expiration; } public User getUser() { diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 6246d2494..930c4fa46 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -62,13 +62,13 @@ public class LoginService { if (serviceAccountToken != null && serviceAccountToken.equals(token)) { return new LoginResult(new ServiceAccountUser()); } - long userId = tokenManager.verifyToken(token); + TokenManager.TokenData tokenData = tokenManager.verifyToken(token); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", userId))); + new Columns.All(), new Condition.Equals("id", tokenData.getUserId()))); if (user != null) { checkUserEnabled(user); } - return new LoginResult(user); + return new LoginResult(user, tokenData.getExpiration()); } public LoginResult login(String email, String password, Integer code) throws StorageException { diff --git a/src/main/java/org/traccar/api/signature/TokenManager.java b/src/main/java/org/traccar/api/signature/TokenManager.java index 3019e12b9..824433b08 100644 --- a/src/main/java/org/traccar/api/signature/TokenManager.java +++ b/src/main/java/org/traccar/api/signature/TokenManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -35,11 +35,19 @@ public class TokenManager { private final ObjectMapper objectMapper; private final CryptoManager cryptoManager; - public static class Data { + public static class TokenData { @JsonProperty("u") private long userId; @JsonProperty("e") private Date expiration; + + public long getUserId() { + return userId; + } + + public Date getExpiration() { + return expiration; + } } @Inject @@ -54,7 +62,7 @@ public class TokenManager { public String generateToken( long userId, Date expiration) throws IOException, GeneralSecurityException, StorageException { - Data data = new Data(); + TokenData data = new TokenData(); data.userId = userId; if (expiration != null) { data.expiration = expiration; @@ -65,13 +73,13 @@ public class TokenManager { return Base64.encodeBase64URLSafeString(cryptoManager.sign(encoded)); } - public long verifyToken(String token) throws IOException, GeneralSecurityException, StorageException { + public TokenData verifyToken(String token) throws IOException, GeneralSecurityException, StorageException { byte[] encoded = cryptoManager.verify(Base64.decodeBase64(token)); - Data data = objectMapper.readValue(encoded, Data.class); + TokenData data = objectMapper.readValue(encoded, TokenData.class); if (data.expiration.before(new Date())) { throw new SecurityException("Token has expired"); } - return data.userId; + return data; } } -- cgit v1.2.3 From fc8678b22929026e6c62284add8ff1cbca247f20 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Nov 2023 08:18:32 -0800 Subject: Store session expiration --- src/main/java/org/traccar/api/resource/SessionResource.java | 6 +++++- .../java/org/traccar/api/security/SecurityRequestFilter.java | 7 +++++-- src/main/java/org/traccar/api/security/UserPrincipal.java | 11 +++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 3e80e0020..0435f4f92 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -17,6 +17,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; import org.traccar.api.security.CodeRequiredException; +import org.traccar.api.security.LoginResult; import org.traccar.api.security.LoginService; import org.traccar.api.signature.TokenManager; import org.traccar.database.OpenIdProvider; @@ -61,6 +62,7 @@ import java.net.URI; public class SessionResource extends BaseResource { public static final String USER_ID_KEY = "userId"; + public static final String EXPIRATION_KEY = "expiration"; public static final String USER_COOKIE_KEY = "user"; public static final String PASS_COOKIE_KEY = "password"; @@ -82,9 +84,11 @@ public class SessionResource extends BaseResource { public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException { if (token != null) { - User user = loginService.login(token).getUser(); + LoginResult loginResult = loginService.login(token); + User user = loginResult.getUser(); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); + request.getSession().setAttribute(EXPIRATION_KEY, loginResult.getExpiration()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return user; } diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index e308024da..c33a80015 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -38,6 +38,7 @@ import java.io.IOException; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; +import java.util.Date; public class SecurityRequestFilter implements ContainerRequestFilter { @@ -92,7 +93,8 @@ public class SecurityRequestFilter implements ContainerRequestFilter { User user = loginResult.getUser(); if (user != null) { statisticsManager.registerRequest(user.getId()); - securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); + securityContext = new UserSecurityContext( + new UserPrincipal(user.getId(), loginResult.getExpiration())); } } catch (StorageException | GeneralSecurityException | IOException e) { throw new WebApplicationException(e); @@ -101,12 +103,13 @@ public class SecurityRequestFilter implements ContainerRequestFilter { } else if (request.getSession() != null) { Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY); + Date expiration = (Date) request.getSession().getAttribute(SessionResource.EXPIRATION_KEY); if (userId != null) { User user = injector.getInstance(PermissionsService.class).getUser(userId); if (user != null) { user.checkDisabled(); statisticsManager.registerRequest(userId); - securityContext = new UserSecurityContext(new UserPrincipal(userId)); + securityContext = new UserSecurityContext(new UserPrincipal(userId, expiration)); } } diff --git a/src/main/java/org/traccar/api/security/UserPrincipal.java b/src/main/java/org/traccar/api/security/UserPrincipal.java index 18b84a0e1..83bd06fe9 100644 --- a/src/main/java/org/traccar/api/security/UserPrincipal.java +++ b/src/main/java/org/traccar/api/security/UserPrincipal.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -16,19 +16,26 @@ package org.traccar.api.security; import java.security.Principal; +import java.util.Date; public class UserPrincipal implements Principal { private final long userId; + private final Date expiration; - public UserPrincipal(long userId) { + public UserPrincipal(long userId, Date expiration) { this.userId = userId; + this.expiration = expiration; } public Long getUserId() { return userId; } + public Date getExpiration() { + return expiration; + } + @Override public String getName() { return null; -- cgit v1.2.3 From b73c8246c2023feae9eb5332a69f0ab8a1cd4e3d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Nov 2023 08:21:33 -0800 Subject: Limit token expiration extension --- src/main/java/org/traccar/api/resource/SessionResource.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 0435f4f92..02c9837f0 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -181,6 +181,10 @@ public class SessionResource extends BaseResource { @POST public String requestToken( @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { + Date currentExpiration = (Date) request.getSession().getAttribute(EXPIRATION_KEY); + if (currentExpiration != null && currentExpiration.before(expiration)) { + expiration = currentExpiration; + } return tokenManager.generateToken(getUserId(), expiration); } -- cgit v1.2.3 From a943126d3cdb4d2e8c4c314d487736267daf171e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Nov 2023 08:38:55 -0800 Subject: Remove cookie password login --- .../org/traccar/api/resource/SessionResource.java | 36 +--------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 02c9837f0..dc517277e 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -21,7 +21,6 @@ import org.traccar.api.security.LoginResult; import org.traccar.api.security.LoginService; import org.traccar.api.signature.TokenManager; import org.traccar.database.OpenIdProvider; -import org.traccar.helper.DataConverter; import org.traccar.helper.LogAction; import org.traccar.helper.WebHelper; import org.traccar.model.User; @@ -34,7 +33,6 @@ import com.nimbusds.oauth2.sdk.ParseException; import jakarta.annotation.Nullable; import jakarta.annotation.security.PermitAll; import jakarta.inject.Inject; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; @@ -50,8 +48,6 @@ import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import java.io.IOException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.Date; import java.net.URI; @@ -63,8 +59,6 @@ public class SessionResource extends BaseResource { public static final String USER_ID_KEY = "userId"; public static final String EXPIRATION_KEY = "expiration"; - public static final String USER_COOKIE_KEY = "user"; - public static final String PASS_COOKIE_KEY = "password"; @Inject private LoginService loginService; @@ -95,39 +89,11 @@ public class SessionResource extends BaseResource { } Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); - if (userId == null) { - - Cookie[] cookies = request.getCookies(); - String email = null, password = null; - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals(USER_COOKIE_KEY)) { - byte[] emailBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); - email = new String(emailBytes, StandardCharsets.UTF_8); - } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { - byte[] passwordBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); - password = new String(passwordBytes, StandardCharsets.UTF_8); - } - } - } - if (email != null && password != null) { - User user = loginService.login(email, password, null).getUser(); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); - return user; - } - } - - } else { - + if (userId != null) { User user = permissionsService.getUser(userId); if (user != null) { return user; } - } throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); -- cgit v1.2.3 From e0d67dd1771e7b265e98bb18ab5359fc335ca9c4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 28 Nov 2023 07:10:00 -0800 Subject: Support Glonass and GNSS NMEA --- src/main/java/org/traccar/protocol/T55ProtocolDecoder.java | 10 ++++++---- src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java | 9 +++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java index b18359b3f..9e7518ce5 100644 --- a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java @@ -41,7 +41,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN_GPRMC = new PatternBuilder() - .text("$GPRMC,") + .text("$") + .expression("G[PLN]RMC,") .number("(dd)(dd)(dd).?d*,") // time (hhmmss) .expression("([AV]),") // validity .number("(dd)(dd.d+),") // latitude @@ -64,7 +65,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { .compile(); private static final Pattern PATTERN_GPGGA = new PatternBuilder() - .text("$GPGGA,") + .text("$") + .expression("G[PLN]GGA,") .number("(dd)(dd)(dd).?d*,") // time (hhmmss) .number("(d+)(dd.d+),") // latitude .expression("([NS]),") @@ -444,9 +446,9 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { } } else if (sentence.matches("^[0-9A-F]+$")) { getDeviceSession(channel, remoteAddress, sentence); - } else if (sentence.startsWith("$GPRMC")) { + } else if (sentence.startsWith("RMC", 3)) { return decodeGprmc(deviceSession, sentence, remoteAddress, channel); - } else if (sentence.startsWith("$GPGGA") && deviceSession != null) { + } else if (sentence.startsWith("GGA", 3) && deviceSession != null) { return decodeGpgga(deviceSession, sentence); } else if (sentence.startsWith("$GPRMA") && deviceSession != null) { return decodeGprma(deviceSession, sentence); diff --git a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java index 7b9841d68..91020714c 100644 --- a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java @@ -17,6 +17,15 @@ public class T55ProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, text( "$PUBX,00,130209.00,3650.51159,N,01346.10602,E,785.947,D3,4.1,5.2,0.163,87.43,-0.054,7.0,0.88,1.21,0.88,24,01012,0*6D")); + verifyPosition(decoder, text( + "$GNRMC,164414.90,A,4650.5156500,N,01246.1059604,E,0.018,,091123,,,A,V*15")); + + verifyPosition(decoder, text( + "$GNGGA,164414.90,4650.5156500,N,01246.1059604,E,1,12,0.84,740.729,M,44.804,M,,*4E")); + + verifyNull(decoder, text( + "$GNGLL,4650.5156500,N,01246.1059604,E,164414.90,A,A*77")); + verifyPosition(decoder, text( "QZE,868994033976700,35,28062020,113553,22.13673,114.57263,0,22,A,0")); -- cgit v1.2.3 From 8f1c0e94ebe29c08ff94a98e2ea53c22732768ad Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Dec 2023 14:04:15 -0800 Subject: Support GL530MG sensors --- .../java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 11 +++++++---- .../org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 4 ++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 5ee3761dd..a73981614 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -649,11 +649,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .expression(PATTERN_LOCATION.pattern()) .expression(")+)") .groupBegin() - .number("d{1,2},,") - .number("(d{1,3}),") // battery + .number("d{1,2},") + .number("(d{1,5})?,") // battery + .number("(d{1,3}),") // battery level .number("[01],") // mode .number("(?:[01])?,") // motion - .number("(?:-?d{1,2}.d)?,") // temperature + .number("(-?d{1,2}.d)?,") // temperature .or() .number("(d{1,7}.d)?,") // odometer .number("(d{5}:dd:dd)?,") // hour meter @@ -721,8 +722,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } if (parser.hasNext()) { - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); } + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); if (parser.hasNext()) { position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 037c8f75a..199012ca0 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+RESP:GTFRI,710303,868487004352084,GL530MG,0,0,1,1,16.6,0,9.4,121.307910,31.127837,20230815050629,0460,0000,1815,B93B,26,0,8964,90,1,0,26.6,20230815130830,0174$"), + Position.PREFIX_TEMP + 1, 26.6); + verifyPosition(decoder, buffer( "+BUFF:GTFRI,8020040200,866314060249032,,12194,10,1,3,0.0,0,20.1,-71.596533,-33.524718,20230926200338,0730,0001,772A,052B253E,02,0,0.0,,,,,0,420000,,,,20230926200340,1549$")); -- cgit v1.2.3 From f93d28f8677e646eea0ac319e9aa3dcc47194bac Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Dec 2023 14:23:39 -0800 Subject: Add FMX6XX driver id --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 45afbd0f7..537990265 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -34,6 +34,7 @@ import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.HashMap; @@ -628,6 +629,14 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { decodeNetwork(position, model); + if (model != null && model.matches("FM.6..")) { + Long driverMsb = (Long) position.getAttributes().get("io195"); + Long driverLsb = (Long) position.getAttributes().get("io196"); + if (driverMsb != null && driverLsb != null) { + String driver = new String(ByteBuffer.allocate(16).putLong(driverMsb).putLong(driverLsb).array()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, driver); + } + } } private List parseData( -- cgit v1.2.3 From f3f12a2ff295d8e60a87e521d09022a2c09763cf Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 3 Dec 2023 08:19:32 -0800 Subject: Use is empty --- src/main/java/org/traccar/session/cache/CacheManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 58320cf29..0aadb3692 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -381,7 +381,7 @@ public class CacheManager implements BroadcastInterface { var key = new CacheKey(clazz, id); deviceCache.computeIfPresent(key, (k, value) -> { value.release(deviceId); - return value.getReferences().size() > 0 ? value : null; + return value.getReferences().isEmpty() ? null : value; }); })); devicePositions.remove(deviceId); -- cgit v1.2.3 From 1efe470d4df335dfaaad5a9e2c6417c24d8864e1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 3 Dec 2023 12:12:57 -0800 Subject: Move find driver method --- src/main/java/org/traccar/notification/NotificationFormatter.java | 4 +++- src/main/java/org/traccar/session/cache/CacheManager.java | 7 ------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java index 85e8a54bb..e994729c0 100644 --- a/src/main/java/org/traccar/notification/NotificationFormatter.java +++ b/src/main/java/org/traccar/notification/NotificationFormatter.java @@ -19,6 +19,7 @@ package org.traccar.notification; import org.apache.velocity.VelocityContext; import org.traccar.helper.model.UserUtil; import org.traccar.model.Device; +import org.traccar.model.Driver; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Maintenance; @@ -66,7 +67,8 @@ public class NotificationFormatter { } String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID); if (driverUniqueId != null) { - velocityContext.put("driver", cacheManager.findDriverByUniqueId(device.getId(), driverUniqueId)); + velocityContext.put("driver", cacheManager.getDeviceObjects(device.getId(), Driver.class).stream() + .filter(driver -> driver.getUniqueId().equals(driverUniqueId)).findFirst().orElse(null)); } return textTemplateFormatter.formatMessage(velocityContext, event.getType(), templatePath); diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 0aadb3692..4b6422de2 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -155,13 +155,6 @@ public class CacheManager implements BroadcastInterface { } } - public Driver findDriverByUniqueId(long deviceId, String driverUniqueId) { - return getDeviceObjects(deviceId, Driver.class).stream() - .filter(driver -> driver.getUniqueId().equals(driverUniqueId)) - .findFirst() - .orElse(null); - } - public void addDevice(long deviceId) throws StorageException { try { lock.writeLock().lock(); -- cgit v1.2.3 From 8999283ee7344fd7ec33c8a6cb5a7999e0592074 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 3 Dec 2023 14:08:07 -0800 Subject: Update broadcast interface --- .../java/org/traccar/api/BaseObjectResource.java | 7 +- .../traccar/api/resource/PermissionsResource.java | 6 +- .../org/traccar/api/resource/ServerResource.java | 3 +- .../traccar/broadcast/BaseBroadcastService.java | 52 ++++++---- .../org/traccar/broadcast/BroadcastInterface.java | 8 +- .../org/traccar/broadcast/BroadcastMessage.java | 113 +++++++++++++++++++-- .../org/traccar/broadcast/ObjectOperation.java | 7 ++ .../traccar/notificators/NotificatorFirebase.java | 3 +- .../traccar/notificators/NotificatorTraccar.java | 3 +- .../org/traccar/session/ConnectionManager.java | 5 +- .../org/traccar/session/cache/CacheManager.java | 18 ++-- 11 files changed, 178 insertions(+), 47 deletions(-) create mode 100644 src/main/java/org/traccar/broadcast/ObjectOperation.java diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 2aaed2bb5..02e1c2cbe 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -17,6 +17,7 @@ package org.traccar.api; import org.traccar.api.security.ServiceAccountUser; +import org.traccar.broadcast.ObjectOperation; import org.traccar.helper.LogAction; import org.traccar.model.BaseModel; import org.traccar.model.Group; @@ -74,8 +75,8 @@ public abstract class BaseObjectResource extends BaseResour if (getUserId() != ServiceAccountUser.ID) { storage.addPermission(new Permission(User.class, getUserId(), baseClass, entity.getId())); - cacheManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId()); - connectionManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId()); + cacheManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId(), true); + connectionManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId(), true); LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId()); } @@ -110,7 +111,7 @@ public abstract class BaseObjectResource extends BaseResour new Condition.Equals("id", entity.getId()))); } } - cacheManager.updateOrInvalidate(true, entity); + cacheManager.updateOrInvalidate(true, entity, ObjectOperation.UPDATE); LogAction.edit(getUserId(), entity); return Response.ok(entity).build(); diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java index e8e4e96eb..2a8ac62f7 100644 --- a/src/main/java/org/traccar/api/resource/PermissionsResource.java +++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java @@ -74,7 +74,8 @@ public class PermissionsResource extends BaseResource { cacheManager.invalidatePermission( true, permission.getOwnerClass(), permission.getOwnerId(), - permission.getPropertyClass(), permission.getPropertyId()); + permission.getPropertyClass(), permission.getPropertyId(), + true); LogAction.link(getUserId(), permission.getOwnerClass(), permission.getOwnerId(), permission.getPropertyClass(), permission.getPropertyId()); @@ -99,7 +100,8 @@ public class PermissionsResource extends BaseResource { cacheManager.invalidatePermission( true, permission.getOwnerClass(), permission.getOwnerId(), - permission.getPropertyClass(), permission.getPropertyId()); + permission.getPropertyClass(), permission.getPropertyId(), + false); LogAction.unlink(getUserId(), permission.getOwnerClass(), permission.getOwnerId(), permission.getPropertyClass(), permission.getPropertyId()); diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 8149ec3b8..bcd36a32e 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -16,6 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; +import org.traccar.broadcast.ObjectOperation; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.OpenIdProvider; @@ -111,7 +112,7 @@ public class ServerResource extends BaseResource { storage.updateObject(entity, new Request( new Columns.Exclude("id"), new Condition.Equals("id", entity.getId()))); - cacheManager.updateOrInvalidate(true, entity); + cacheManager.updateOrInvalidate(true, entity, ObjectOperation.UPDATE); LogAction.edit(getUserId(), entity); return Response.ok(entity).build(); } diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java index a95d333f2..bb220d2bb 100644 --- a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java @@ -16,7 +16,6 @@ package org.traccar.broadcast; import java.util.HashSet; -import java.util.Map; import java.util.Set; import org.traccar.model.BaseModel; @@ -69,9 +68,16 @@ public abstract class BaseBroadcastService implements BroadcastService { } @Override - public void invalidateObject(boolean local, Class clazz, long id) { + public void invalidateObject( + boolean local, + Class clazz, long id, + ObjectOperation operation) { BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz), id)); + var invalidateObject = new BroadcastMessage.InvalidateObject(); + invalidateObject.setClazz(Permission.getKey(clazz)); + invalidateObject.setId(id); + invalidateObject.setOperation(operation); + message.setInvalidateObject(invalidateObject); sendMessage(message); } @@ -79,9 +85,16 @@ public abstract class BaseBroadcastService implements BroadcastService { public void invalidatePermission( boolean local, Class clazz1, long id1, - Class clazz2, long id2) { + Class clazz2, long id2, + boolean link) { BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); + var invalidatePermission = new BroadcastMessage.InvalidatePermission(); + invalidatePermission.setClazz1(Permission.getKey(clazz1)); + invalidatePermission.setId1(id1); + invalidatePermission.setClazz2(Permission.getKey(clazz2)); + invalidatePermission.setId2(id2); + invalidatePermission.setLink(link); + message.setInvalidatePermission(invalidatePermission); sendMessage(message); } @@ -96,22 +109,19 @@ public abstract class BaseBroadcastService implements BroadcastService { listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); } else if (message.getCommandDeviceId() != null) { listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); - } else if (message.getChanges() != null) { - var iterator = message.getChanges().entrySet().iterator(); - if (iterator.hasNext()) { - var first = iterator.next(); - if (iterator.hasNext()) { - var second = iterator.next(); - listeners.forEach(listener -> listener.invalidatePermission( - false, - Permission.getKeyClass(first.getKey()), first.getValue(), - Permission.getKeyClass(second.getKey()), second.getValue())); - } else { - listeners.forEach(listener -> listener.invalidateObject( - false, - Permission.getKeyClass(first.getKey()), first.getValue())); - } - } + } else if (message.getInvalidateObject() != null) { + var invalidateObject = message.getInvalidateObject(); + listeners.forEach(listeners -> listeners.invalidateObject( + false, + Permission.getKeyClass(invalidateObject.getClazz()), invalidateObject.getId(), + invalidateObject.getOperation())); + } else if (message.getInvalidatePermission() != null) { + var invalidatePermission = message.getInvalidatePermission(); + listeners.forEach(listener -> listener.invalidatePermission( + false, + Permission.getKeyClass(invalidatePermission.getClazz1()), invalidatePermission.getId1(), + Permission.getKeyClass(invalidatePermission.getClazz2()), invalidatePermission.getId2(), + invalidatePermission.getLink())); } } diff --git a/src/main/java/org/traccar/broadcast/BroadcastInterface.java b/src/main/java/org/traccar/broadcast/BroadcastInterface.java index 673ebd8b8..ededbaa1a 100644 --- a/src/main/java/org/traccar/broadcast/BroadcastInterface.java +++ b/src/main/java/org/traccar/broadcast/BroadcastInterface.java @@ -34,12 +34,16 @@ public interface BroadcastInterface { default void updateCommand(boolean local, long deviceId) { } - default void invalidateObject(boolean local, Class clazz, long id) { + default void invalidateObject( + boolean local, + Class clazz, long id, + ObjectOperation operation) { } default void invalidatePermission( boolean local, Class clazz1, long id1, - Class clazz2, long id2) { + Class clazz2, long id2, + boolean link) { } } diff --git a/src/main/java/org/traccar/broadcast/BroadcastMessage.java b/src/main/java/org/traccar/broadcast/BroadcastMessage.java index 985848d04..6fe2d8b35 100644 --- a/src/main/java/org/traccar/broadcast/BroadcastMessage.java +++ b/src/main/java/org/traccar/broadcast/BroadcastMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -19,8 +19,6 @@ import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; -import java.util.Map; - public class BroadcastMessage { private Device device; @@ -73,13 +71,112 @@ public class BroadcastMessage { this.commandDeviceId = commandDeviceId; } - private Map changes; + public static class InvalidateObject { + + private String clazz; + + public String getClazz() { + return clazz; + } + + public void setClazz(String clazz) { + this.clazz = clazz; + } + + private long id; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + private ObjectOperation operation; + + public ObjectOperation getOperation() { + return operation; + } + + public void setOperation(ObjectOperation operation) { + this.operation = operation; + } - public Map getChanges() { - return changes; } - public void setChanges(Map changes) { - this.changes = changes; + private InvalidateObject invalidateObject; + + public InvalidateObject getInvalidateObject() { + return invalidateObject; + } + + public void setInvalidateObject(InvalidateObject invalidateObject) { + this.invalidateObject = invalidateObject; } + + public static class InvalidatePermission { + + private String clazz1; + + public String getClazz1() { + return clazz1; + } + + public void setClazz1(String clazz1) { + this.clazz1 = clazz1; + } + + private long id1; + + public long getId1() { + return id1; + } + + public void setId1(long id1) { + this.id1 = id1; + } + + private String clazz2; + + public String getClazz2() { + return clazz2; + } + + public void setClazz2(String clazz2) { + this.clazz2 = clazz2; + } + + private long id2; + + public long getId2() { + return id2; + } + + public void setId2(long id2) { + this.id2 = id2; + } + + private boolean link; + + public boolean getLink() { + return link; + } + + public void setLink(boolean link) { + this.link = link; + } + + } + + private InvalidatePermission invalidatePermission; + + public InvalidatePermission getInvalidatePermission() { + return invalidatePermission; + } + + public void setInvalidatePermission(InvalidatePermission invalidatePermission) { + this.invalidatePermission = invalidatePermission; + } + } diff --git a/src/main/java/org/traccar/broadcast/ObjectOperation.java b/src/main/java/org/traccar/broadcast/ObjectOperation.java new file mode 100644 index 000000000..27e5fb253 --- /dev/null +++ b/src/main/java/org/traccar/broadcast/ObjectOperation.java @@ -0,0 +1,7 @@ +package org.traccar.broadcast; + +public enum ObjectOperation { + ADD, + UPDATE, + DELETE, +} diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index be95fb28e..0402db49d 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -29,6 +29,7 @@ import com.google.firebase.messaging.MessagingErrorCode; import com.google.firebase.messaging.MulticastMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.broadcast.ObjectOperation; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; @@ -135,7 +136,7 @@ public class NotificatorFirebase implements Notificator { storage.updateObject(user, new Request( new Columns.Include("attributes"), new Condition.Equals("id", user.getId()))); - cacheManager.updateOrInvalidate(true, user); + cacheManager.updateOrInvalidate(true, user, ObjectOperation.UPDATE); } } catch (FirebaseMessagingException | StorageException e) { LOGGER.warn("Firebase error", e); diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index e354adccb..f693e9f30 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java @@ -18,6 +18,7 @@ package org.traccar.notificators; import com.fasterxml.jackson.annotation.JsonProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.broadcast.ObjectOperation; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; @@ -128,7 +129,7 @@ public class NotificatorTraccar implements Notificator { storage.updateObject(user, new Request( new Columns.Include("attributes"), new Condition.Equals("id", user.getId()))); - cacheManager.updateOrInvalidate(true, user); + cacheManager.updateOrInvalidate(true, user, ObjectOperation.UPDATE); } } catch (StorageException e) { LOGGER.warn("Push error", e); diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 28214840d..0b13a5a72 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -330,8 +330,9 @@ public class ConnectionManager implements BroadcastInterface { public synchronized void invalidatePermission( boolean local, Class clazz1, long id1, - Class clazz2, long id2) { - if (clazz1.equals(User.class) && clazz2.equals(Device.class)) { + Class clazz2, long id2, + boolean link) { + if (link && clazz1.equals(User.class) && clazz2.equals(Device.class)) { if (listeners.containsKey(id1)) { userDevices.get(id1).add(id2); deviceUsers.put(id2, new HashSet<>(List.of(id1))); diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 4b6422de2..c40916218 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -19,6 +19,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.broadcast.BroadcastInterface; import org.traccar.broadcast.BroadcastService; +import org.traccar.broadcast.ObjectOperation; import org.traccar.config.Config; import org.traccar.model.Attribute; import org.traccar.model.BaseModel; @@ -201,12 +202,15 @@ public class CacheManager implements BroadcastInterface { } @Override - public void invalidateObject(boolean local, Class clazz, long id) { + public void invalidateObject( + boolean local, + Class clazz, long id, + ObjectOperation operation) { try { var object = storage.getObject(clazz, new Request( new Columns.All(), new Condition.Equals("id", id))); if (object != null) { - updateOrInvalidate(local, object); + updateOrInvalidate(local, object, operation); } else { invalidate(clazz, id); } @@ -215,9 +219,10 @@ public class CacheManager implements BroadcastInterface { } } - public void updateOrInvalidate(boolean local, T object) throws StorageException { + public void updateOrInvalidate( + boolean local, T object, ObjectOperation operation) throws StorageException { if (local) { - broadcastService.invalidateObject(true, object.getClass(), object.getId()); + broadcastService.invalidateObject(true, object.getClass(), object.getId(), operation); } if (object instanceof Server) { @@ -262,9 +267,10 @@ public class CacheManager implements BroadcastInterface { public void invalidatePermission( boolean local, Class clazz1, long id1, - Class clazz2, long id2) { + Class clazz2, long id2, + boolean link) { if (local) { - broadcastService.invalidatePermission(true, clazz1, id1, clazz2, id2); + broadcastService.invalidatePermission(true, clazz1, id1, clazz2, id2, link); } try { -- cgit v1.2.3 From 26d09785ffc30be8af27bdc6e9a30f4c5d174d37 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 3 Dec 2023 14:16:00 -0800 Subject: Move class --- src/main/java/org/traccar/api/BaseObjectResource.java | 2 +- src/main/java/org/traccar/api/resource/ServerResource.java | 2 +- src/main/java/org/traccar/broadcast/BaseBroadcastService.java | 1 + src/main/java/org/traccar/broadcast/BroadcastInterface.java | 1 + src/main/java/org/traccar/broadcast/BroadcastMessage.java | 1 + src/main/java/org/traccar/broadcast/ObjectOperation.java | 7 ------- src/main/java/org/traccar/model/ObjectOperation.java | 7 +++++++ src/main/java/org/traccar/notificators/NotificatorFirebase.java | 2 +- src/main/java/org/traccar/notificators/NotificatorTraccar.java | 2 +- src/main/java/org/traccar/session/cache/CacheManager.java | 2 +- 10 files changed, 15 insertions(+), 12 deletions(-) delete mode 100644 src/main/java/org/traccar/broadcast/ObjectOperation.java create mode 100644 src/main/java/org/traccar/model/ObjectOperation.java diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 02e1c2cbe..ebfa93ff0 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -17,7 +17,7 @@ package org.traccar.api; import org.traccar.api.security.ServiceAccountUser; -import org.traccar.broadcast.ObjectOperation; +import org.traccar.model.ObjectOperation; import org.traccar.helper.LogAction; import org.traccar.model.BaseModel; import org.traccar.model.Group; diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index bcd36a32e..59ef642c8 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -16,7 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; -import org.traccar.broadcast.ObjectOperation; +import org.traccar.model.ObjectOperation; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.OpenIdProvider; diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java index bb220d2bb..1c4660320 100644 --- a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java @@ -21,6 +21,7 @@ import java.util.Set; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Event; +import org.traccar.model.ObjectOperation; import org.traccar.model.Permission; import org.traccar.model.Position; diff --git a/src/main/java/org/traccar/broadcast/BroadcastInterface.java b/src/main/java/org/traccar/broadcast/BroadcastInterface.java index ededbaa1a..25fdf4d93 100644 --- a/src/main/java/org/traccar/broadcast/BroadcastInterface.java +++ b/src/main/java/org/traccar/broadcast/BroadcastInterface.java @@ -18,6 +18,7 @@ package org.traccar.broadcast; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Event; +import org.traccar.model.ObjectOperation; import org.traccar.model.Position; public interface BroadcastInterface { diff --git a/src/main/java/org/traccar/broadcast/BroadcastMessage.java b/src/main/java/org/traccar/broadcast/BroadcastMessage.java index 6fe2d8b35..0d15d7495 100644 --- a/src/main/java/org/traccar/broadcast/BroadcastMessage.java +++ b/src/main/java/org/traccar/broadcast/BroadcastMessage.java @@ -17,6 +17,7 @@ package org.traccar.broadcast; import org.traccar.model.Device; import org.traccar.model.Event; +import org.traccar.model.ObjectOperation; import org.traccar.model.Position; public class BroadcastMessage { diff --git a/src/main/java/org/traccar/broadcast/ObjectOperation.java b/src/main/java/org/traccar/broadcast/ObjectOperation.java deleted file mode 100644 index 27e5fb253..000000000 --- a/src/main/java/org/traccar/broadcast/ObjectOperation.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.traccar.broadcast; - -public enum ObjectOperation { - ADD, - UPDATE, - DELETE, -} diff --git a/src/main/java/org/traccar/model/ObjectOperation.java b/src/main/java/org/traccar/model/ObjectOperation.java new file mode 100644 index 000000000..b462580bb --- /dev/null +++ b/src/main/java/org/traccar/model/ObjectOperation.java @@ -0,0 +1,7 @@ +package org.traccar.model; + +public enum ObjectOperation { + ADD, + UPDATE, + DELETE, +} diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index 0402db49d..a39683b2b 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -29,7 +29,7 @@ import com.google.firebase.messaging.MessagingErrorCode; import com.google.firebase.messaging.MulticastMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.traccar.broadcast.ObjectOperation; +import org.traccar.model.ObjectOperation; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index f693e9f30..82e1584a5 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java @@ -18,7 +18,7 @@ package org.traccar.notificators; import com.fasterxml.jackson.annotation.JsonProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.traccar.broadcast.ObjectOperation; +import org.traccar.model.ObjectOperation; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index c40916218..dc9c86ef3 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -19,7 +19,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.broadcast.BroadcastInterface; import org.traccar.broadcast.BroadcastService; -import org.traccar.broadcast.ObjectOperation; +import org.traccar.model.ObjectOperation; import org.traccar.config.Config; import org.traccar.model.Attribute; import org.traccar.model.BaseModel; -- cgit v1.2.3 From f26a894807be6c2ea06e28d3ce33d7aea34a1ade Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 5 Dec 2023 21:46:34 -0800 Subject: Additional Positrex parameters --- .../java/org/traccar/protocol/PositrexProtocolDecoder.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java index ff4825e8d..82ae2c134 100644 --- a/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java @@ -95,6 +95,17 @@ public class PositrexProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); position.setCourse(buf.readUnsignedByte() * 2); + position.set(Position.PREFIX_IO, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + buf.readUnsignedInt(); // report begin + buf.readUnsignedInt(); // report end + buf.readUnsignedInt(); // number of records + + if (buf.isReadable()) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + } + return position; } -- cgit v1.2.3 From 87b2f36a487edc54cf4d8a1e27ce338f67bf8d55 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 10 Dec 2023 14:04:52 -0800 Subject: Include user id in web logs --- src/main/java/org/traccar/web/WebRequestLog.java | 57 ++++++++++++++++++++++++ src/main/java/org/traccar/web/WebServer.java | 4 +- 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/traccar/web/WebRequestLog.java diff --git a/src/main/java/org/traccar/web/WebRequestLog.java b/src/main/java/org/traccar/web/WebRequestLog.java new file mode 100644 index 000000000..3f3286003 --- /dev/null +++ b/src/main/java/org/traccar/web/WebRequestLog.java @@ -0,0 +1,57 @@ +/* + * 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.web; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.RequestLog; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.DateCache; +import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.traccar.api.resource.SessionResource; + +import java.util.Locale; +import java.util.TimeZone; + +public class WebRequestLog extends ContainerLifeCycle implements RequestLog { + + private final Writer writer; + + private final DateCache dateCache = new DateCache( + "dd/MMM/yyyy:HH:mm:ss ZZZ", Locale.getDefault(), TimeZone.getTimeZone("GMT")); + + public WebRequestLog(Writer writer) { + this.writer = writer; + addBean(writer); + } + + @Override + public void log(Request request, Response response) { + try { + Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY); + writer.write(String.format("%s - %s [%s] \"%s %s %s\" %d %d", + request.getRemoteHost(), + userId != null ? String.valueOf(userId) : "-", + dateCache.format(request.getTimeStamp()), + request.getMethod(), + request.getOriginalURI(), + request.getProtocol(), + response.getCommittedMetaData().getStatus(), + response.getHttpChannel().getBytesWritten())); + } catch (Throwable ignored) { + } + } + +} diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index 5f27f7662..4759942b1 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -21,7 +21,6 @@ import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.proxy.AsyncProxyServlet; -import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.RequestLogWriter; import org.eclipse.jetty.server.Server; @@ -115,8 +114,7 @@ public class WebServer implements LifecycleObject { RequestLogWriter logWriter = new RequestLogWriter(config.getString(Keys.WEB_REQUEST_LOG_PATH)); logWriter.setAppend(true); logWriter.setRetainDays(config.getInteger(Keys.WEB_REQUEST_LOG_RETAIN_DAYS)); - CustomRequestLog requestLog = new CustomRequestLog(logWriter, CustomRequestLog.NCSA_FORMAT); - server.setRequestLog(requestLog); + server.setRequestLog(new WebRequestLog(logWriter)); } } -- cgit v1.2.3 From 19e99aa97d3088055b534d06527c1f0fe7c8e094 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 10 Dec 2023 14:12:41 -0800 Subject: Add events to the log --- src/main/java/org/traccar/database/NotificationManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 03cfba418..79585d67a 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -23,6 +23,7 @@ import org.traccar.config.Keys; import org.traccar.forward.EventData; import org.traccar.forward.EventForwarder; import org.traccar.geocoder.Geocoder; +import org.traccar.helper.DateUtil; import org.traccar.model.Calendar; import org.traccar.model.Device; import org.traccar.model.Event; @@ -107,6 +108,14 @@ public class NotificationManager { }) .collect(Collectors.toUnmodifiableList()); + Device device = cacheManager.getObject(Device.class, event.getDeviceId()); + LOGGER.info( + "Event id: {}, time: {}, type: {}, notifications: {}", + device.getUniqueId(), + DateUtil.formatDate(event.getEventTime(), false), + event.getType(), + notifications.size()); + if (!notifications.isEmpty()) { if (position != null && position.getAddress() == null && geocodeOnRequest && geocoder != null) { position.setAddress(geocoder.getAddress(position.getLatitude(), position.getLongitude(), null)); -- cgit v1.2.3 From f1aa481156249b5e466e1a47685171af92b2f9a0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 14 Dec 2023 07:38:59 -0800 Subject: Add EasyTrack OBD support --- .../traccar/protocol/EasyTrackProtocolDecoder.java | 70 +++++++++++++++++++--- .../protocol/EasyTrackProtocolDecoderTest.java | 3 + 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java index 805cf1197..b10ff4c64 100644 --- a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -79,26 +79,45 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); + private static final Pattern PATTERN_OBD = new PatternBuilder() + .text("*").expression("..,") // manufacturer + .number("(d+),") // imei + .text("OB,") // command + .text("BD$") + .number("V(d+.d);") // battery + .number("R(d+);") // rpm + .number("S(d+);") // speed + .number("P(d+.d);") // throttle + .number("O(d+.d);") // engine load + .number("C(d+);") // coolant temperature + .number("L(d+.d);") // fuel level + .number("[XY][MH]d+.d+;") + .number("M(d+);") // mileage + .number("F(d+.d+);") // fuel consumption + .number("T(d+);") // engine time + .any() + .compile(); + private String decodeAlarm(long status) { - if ((status & 0x02000000) != 0) { + if ((status & 0x02000000L) != 0) { return Position.ALARM_GEOFENCE_ENTER; } - if ((status & 0x04000000) != 0) { + if ((status & 0x04000000L) != 0) { return Position.ALARM_GEOFENCE_EXIT; } - if ((status & 0x08000000) != 0) { + if ((status & 0x08000000L) != 0) { return Position.ALARM_LOW_BATTERY; } - if ((status & 0x20000000) != 0) { + if ((status & 0x20000000L) != 0) { return Position.ALARM_VIBRATION; } - if ((status & 0x80000000) != 0) { + if ((status & 0x80000000L) != 0) { return Position.ALARM_OVERSPEED; } - if ((status & 0x00010000) != 0) { + if ((status & 0x00010000L) != 0) { return Position.ALARM_SOS; } - if ((status & 0x00040000) != 0) { + if ((status & 0x00040000L) != 0) { return Position.ALARM_POWER_CUT; } return null; @@ -115,7 +134,9 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { channel.writeAndFlush(new NetworkMessage(sentence + "#", remoteAddress)); } - if (type.equals("JZ")) { + if (type.equals("OB")) { + return decodeObd(channel, remoteAddress, sentence); + } else if (type.equals("JZ")) { return decodeCell(channel, remoteAddress, sentence); } else { return decodeLocation(channel, remoteAddress, sentence); @@ -219,4 +240,35 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_OBD, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_RPM, parser.nextInt()); + position.set(Position.KEY_OBD_SPEED, parser.nextInt()); + position.set(Position.KEY_THROTTLE, parser.nextDouble()); + position.set(Position.KEY_ENGINE_LOAD, parser.nextDouble()); + position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextInt()); + position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble()); + position.set(Position.KEY_HOURS, parser.nextInt()); + + return position; + } + } diff --git a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java index bcd9aea45..d40463c1e 100644 --- a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class EasyTrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new EasyTrackProtocolDecoder(null)); + verifyAttributes(decoder, text( + "*ET,358999999999916,OB,BD$V14.2;R08258;S166;P058.4;O079.2;C025;L081.5;XM091.393;M722379;F352.956;T0037184;A01;B00;D00;GX3;GY-6;GZ-268;@4#")); + verifyNotNull(decoder, text( "*ET,354522180593498,JZ,0,20222,262,724,4#")); -- cgit v1.2.3 From 2426e050ca6d4fb163e4163a8f713da32064aaf7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 15 Dec 2023 08:38:41 -0800 Subject: Fix test formatting --- .../org/traccar/protocol/SuntechProtocolDecoderTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index cbb68132f..22afe559a 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -233,13 +233,13 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { decoder.setIncludeAdc(true); verifyAttribute(decoder, buffer( - "ST600STT;008594432;20;492;20200212;18:58:30;060bb0e1;334;20;36bb;45;+19.337897;-099.064489;000.398;000.00;12;1;5049883;13.61;100100;2;1198;013762;4.2;1;4.68"), + "ST600STT;008594432;20;492;20200212;18:58:30;060bb0e1;334;20;36bb;45;+19.337897;-099.064489;000.398;000.00;12;1;5049883;13.61;100100;2;1198;013762;4.2;1;4.68"), Position.PREFIX_ADC + 1, 4.68); decoder.setIncludeTemp(true); verifyAttribute(decoder, buffer( - "ST600STT;008350848;35;523;20191102;13:49:46;0bf14fdb;334;20;2f19;57;+20.466737;-100.825455;000.006;000.00;11;1;10274175;11.36;00000000;1;0300;018353;4.2;1;0.00;;;;00000000000000;0;28EE56B911160234:+13.7;:;:"), + "ST600STT;008350848;35;523;20191102;13:49:46;0bf14fdb;334;20;2f19;57;+20.466737;-100.825455;000.006;000.00;11;1;10274175;11.36;00000000;1;0300;018353;4.2;1;0.00;;;;00000000000000;0;28EE56B911160234:+13.7;:;:"), Position.PREFIX_TEMP + 2, 13.7); verifyPosition(decoder, buffer( @@ -262,7 +262,7 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { decoder.setIncludeRpm(true); verifyAttribute(decoder, buffer( - "ST300STT;907131077;04;706;20190227;23:59:34;cc719;-12.963490;-038.499587;000.067;000.00;7;1;57095;12.50;000000;1;0337;000207;0.0;1;0;012E717F010000;1"), + "ST300STT;907131077;04;706;20190227;23:59:34;cc719;-12.963490;-038.499587;000.067;000.00;7;1;57095;12.50;000000;1;0337;000207;0.0;1;0;012E717F010000;1"), Position.KEY_RPM, 0); } @@ -275,7 +275,7 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { decoder.setHbm(true); verifyAttribute(decoder, buffer( - "ST300ALT;007239104;40;313;20190112;01:07:16;c99139;+04.703287;-074.148897;000.000;189.72;21;1;425512;12.61;100000;33;003188;4.1;1"), + "ST300ALT;007239104;40;313;20190112;01:07:16;c99139;+04.703287;-074.148897;000.000;189.72;21;1;425512;12.61;100000;33;003188;4.1;1"), Position.KEY_HOURS, 3188 * 60000L); } @@ -286,11 +286,11 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { var decoder = inject(new SuntechProtocolDecoder(null)); verifyAttribute(decoder, buffer( - "ST300HTE;511050566;45;308;20200909;13:38:38;0;12.50;001354;0.0;1;0;1;1;0;-27.636632;-052.277933;-27.636675;-052.277947;000.000;002.296;0;00000000000000"), + "ST300HTE;511050566;45;308;20200909;13:38:38;0;12.50;001354;0.0;1;0;1;1;0;-27.636632;-052.277933;-27.636675;-052.277947;000.000;002.296;0;00000000000000"), Position.KEY_DRIVER_UNIQUE_ID, "00000000000000"); verifyAttribute(decoder, buffer( - "ST300HTE;100850001;04;248;20110101;00:13:52;167559;12.28;004005;0.0;1;0;3;3;0;-22.881018;-047.070831;-22.881018;-047.070831;000.000;000.000;0;0;3;0;0;0;01E04D44160000"), + "ST300HTE;100850001;04;248;20110101;00:13:52;167559;12.28;004005;0.0;1;0;3;3;0;-22.881018;-047.070831;-22.881018;-047.070831;000.000;000.000;0;0;3;0;0;0;01E04D44160000"), Position.KEY_DRIVER_UNIQUE_ID, "01E04D44160000"); } -- cgit v1.2.3 From 82b53e48e55cbbe55de152b1b9e63ccc4bb80d04 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 16 Dec 2023 07:31:12 -0800 Subject: Sanitize upload path --- src/main/java/org/traccar/api/resource/ServerResource.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 59ef642c8..1d88e5abc 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -140,7 +140,12 @@ public class ServerResource extends BaseResource { permissionsService.checkAdmin(getUserId()); String root = config.getString(Keys.WEB_OVERRIDE, config.getString(Keys.WEB_PATH)); - var outputPath = Paths.get(root, path); + var rootPath = Paths.get(root).normalize(); + var outputPath = rootPath.resolve(path).normalize(); + if (!outputPath.startsWith(rootPath)) { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + var directoryPath = outputPath.getParent(); if (directoryPath != null) { Files.createDirectories(directoryPath); -- cgit v1.2.3 From fa71241a3c93f1210e5f30fc4195477ad35986ae Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 16 Dec 2023 07:31:42 -0800 Subject: Rename method --- src/main/java/org/traccar/api/resource/ServerResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 1d88e5abc..1ef2a6c33 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -136,7 +136,7 @@ public class ServerResource extends BaseResource { @Path("file/{path}") @POST @Consumes("*/*") - public Response uploadImage(@PathParam("path") String path, File inputFile) throws IOException, StorageException { + public Response uploadFile(@PathParam("path") String path, File inputFile) throws IOException, StorageException { permissionsService.checkAdmin(getUserId()); String root = config.getString(Keys.WEB_OVERRIDE, config.getString(Keys.WEB_PATH)); -- cgit v1.2.3 From 4dc2e86ae5e403143b3c4e2c1a3bd671dfeaf5f8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 16 Dec 2023 07:48:13 -0800 Subject: Better Suntech driver id support --- src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java | 3 ++- src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 86a8bf6fe..53c4a5d02 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -454,9 +454,10 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { if (values.length - index >= 2) { String driverUniqueId = values[index++]; - if (values[index++].equals("1") && !driverUniqueId.isEmpty()) { + if (!driverUniqueId.isEmpty()) { position.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); } + index += 1; // registered } if (isIncludeTemp(deviceSession.getDeviceId())) { diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index 22afe559a..d656bba13 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -293,6 +293,12 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { "ST300HTE;100850001;04;248;20110101;00:13:52;167559;12.28;004005;0.0;1;0;3;3;0;-22.881018;-047.070831;-22.881018;-047.070831;000.000;000.000;0;0;3;0;0;0;01E04D44160000"), Position.KEY_DRIVER_UNIQUE_ID, "01E04D44160000"); + decoder.setHbm(true); + + verifyAttribute(decoder, buffer( + "ST300STT;807469112;45;315;20231215;15:25:03;104147;-16.030168;-047.989150;000.000;000.00;19;1;8600;12.14;000010;1;0456;000373;4.1;1;01B54221010000;0"), + Position.KEY_DRIVER_UNIQUE_ID, "01B54221010000"); + } } -- cgit v1.2.3 From c165968c2eb24b1c4a35dab39174b4df3576551c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 17 Dec 2023 11:43:51 -0800 Subject: Improve cache update performance --- src/main/java/org/traccar/BaseProtocolDecoder.java | 3 +- .../java/org/traccar/api/BaseObjectResource.java | 10 +- .../traccar/api/resource/AttributeResource.java | 6 +- .../org/traccar/api/resource/DeviceResource.java | 2 +- .../traccar/api/resource/PermissionsResource.java | 8 +- .../org/traccar/api/resource/ServerResource.java | 19 +- .../org/traccar/api/resource/UserResource.java | 2 +- .../traccar/broadcast/BaseBroadcastService.java | 37 +- .../org/traccar/broadcast/BroadcastInterface.java | 16 +- .../broadcast/MulticastBroadcastService.java | 2 +- .../traccar/broadcast/RedisBroadcastService.java | 11 +- .../org/traccar/database/NotificationManager.java | 5 +- .../traccar/notificators/NotificatorFirebase.java | 6 +- .../traccar/notificators/NotificatorTraccar.java | 5 +- .../org/traccar/session/ConnectionManager.java | 9 +- .../java/org/traccar/session/cache/CacheGraph.java | 139 ++++++++ .../java/org/traccar/session/cache/CacheKey.java | 4 + .../org/traccar/session/cache/CacheManager.java | 384 ++++++++------------- .../java/org/traccar/session/cache/CacheNode.java | 40 +++ .../java/org/traccar/session/cache/CacheValue.java | 53 --- .../org/traccar/session/cache/WeakValueMap.java | 44 +++ .../events/MaintenanceEventHandlerTest.java | 17 +- 22 files changed, 443 insertions(+), 379 deletions(-) create mode 100644 src/main/java/org/traccar/session/cache/CacheGraph.java create mode 100644 src/main/java/org/traccar/session/cache/CacheNode.java delete mode 100644 src/main/java/org/traccar/session/cache/CacheValue.java create mode 100644 src/main/java/org/traccar/session/cache/WeakValueMap.java diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 97762e8ca..4d4086c3c 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -29,7 +29,6 @@ import org.traccar.model.Position; import org.traccar.session.ConnectionManager; import org.traccar.session.DeviceSession; import org.traccar.session.cache.CacheManager; -import org.traccar.storage.StorageException; import jakarta.inject.Inject; import java.net.InetSocketAddress; @@ -137,7 +136,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { public DeviceSession getDeviceSession(Channel channel, SocketAddress remoteAddress, String... uniqueIds) { try { return connectionManager.getDeviceSession(protocol, channel, remoteAddress, uniqueIds); - } catch (StorageException e) { + } catch (Exception e) { throw new RuntimeException(e); } } diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index ebfa93ff0..2a801221b 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -67,7 +67,7 @@ public abstract class BaseObjectResource extends BaseResour } @POST - public Response add(T entity) throws StorageException { + public Response add(T entity) throws Exception { permissionsService.checkEdit(getUserId(), entity, true); entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); @@ -85,7 +85,7 @@ public abstract class BaseObjectResource extends BaseResour @Path("{id}") @PUT - public Response update(T entity) throws StorageException { + public Response update(T entity) throws Exception { permissionsService.checkEdit(getUserId(), entity, false); permissionsService.checkPermission(baseClass, getUserId(), entity.getId()); @@ -111,7 +111,7 @@ public abstract class BaseObjectResource extends BaseResour new Condition.Equals("id", entity.getId()))); } } - cacheManager.updateOrInvalidate(true, entity, ObjectOperation.UPDATE); + cacheManager.invalidateObject(true, entity.getClass(), entity.getId(), ObjectOperation.UPDATE); LogAction.edit(getUserId(), entity); return Response.ok(entity).build(); @@ -119,12 +119,12 @@ public abstract class BaseObjectResource extends BaseResour @Path("{id}") @DELETE - public Response remove(@PathParam("id") long id) throws StorageException { + public Response remove(@PathParam("id") long id) throws Exception { permissionsService.checkEdit(getUserId(), baseClass, false); permissionsService.checkPermission(baseClass, getUserId(), id); storage.removeObject(baseClass, new Request(new Condition.Equals("id", id))); - cacheManager.invalidate(baseClass, id); + cacheManager.invalidateObject(true, baseClass, id, ObjectOperation.DELETE); LogAction.remove(getUserId(), baseClass, id); diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java index 44f0ef452..52c4d6324 100644 --- a/src/main/java/org/traccar/api/resource/AttributeResource.java +++ b/src/main/java/org/traccar/api/resource/AttributeResource.java @@ -78,21 +78,21 @@ public class AttributeResource extends ExtendedObjectResource { } @POST - public Response add(Attribute entity) throws StorageException { + public Response add(Attribute entity) throws Exception { permissionsService.checkAdmin(getUserId()); return super.add(entity); } @Path("{id}") @PUT - public Response update(Attribute entity) throws StorageException { + public Response update(Attribute entity) throws Exception { permissionsService.checkAdmin(getUserId()); return super.update(entity); } @Path("{id}") @DELETE - public Response remove(@PathParam("id") long id) throws StorageException { + public Response remove(@PathParam("id") long id) throws Exception { permissionsService.checkAdmin(getUserId()); return super.remove(id); } diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index ebc40a9b1..217ccda65 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -128,7 +128,7 @@ public class DeviceResource extends BaseObjectResource { @Path("{id}/accumulators") @PUT - public Response updateAccumulators(DeviceAccumulators entity) throws StorageException { + public Response updateAccumulators(DeviceAccumulators entity) throws Exception { if (permissionsService.notAdmin(getUserId())) { permissionsService.checkManager(getUserId()); permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java index 2a8ac62f7..9e2d21f2c 100644 --- a/src/main/java/org/traccar/api/resource/PermissionsResource.java +++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java @@ -64,7 +64,7 @@ public class PermissionsResource extends BaseResource { @Path("bulk") @POST - public Response add(List> entities) throws StorageException, ClassNotFoundException { + public Response add(List> entities) throws Exception { permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly); checkPermissionTypes(entities); for (LinkedHashMap entity: entities) { @@ -84,13 +84,13 @@ public class PermissionsResource extends BaseResource { } @POST - public Response add(LinkedHashMap entity) throws StorageException, ClassNotFoundException { + public Response add(LinkedHashMap entity) throws Exception { return add(Collections.singletonList(entity)); } @DELETE @Path("bulk") - public Response remove(List> entities) throws StorageException, ClassNotFoundException { + public Response remove(List> entities) throws Exception { permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly); checkPermissionTypes(entities); for (LinkedHashMap entity: entities) { @@ -110,7 +110,7 @@ public class PermissionsResource extends BaseResource { } @DELETE - public Response remove(LinkedHashMap entity) throws StorageException, ClassNotFoundException { + public Response remove(LinkedHashMap entity) throws Exception { return remove(Collections.singletonList(entity)); } diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 1ef2a6c33..66ecc74e1 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -107,14 +107,14 @@ public class ServerResource extends BaseResource { } @PUT - public Response update(Server entity) throws StorageException { + public Response update(Server server) throws Exception { permissionsService.checkAdmin(getUserId()); - storage.updateObject(entity, new Request( + storage.updateObject(server, new Request( new Columns.Exclude("id"), - new Condition.Equals("id", entity.getId()))); - cacheManager.updateOrInvalidate(true, entity, ObjectOperation.UPDATE); - LogAction.edit(getUserId(), entity); - return Response.ok(entity).build(); + new Condition.Equals("id", server.getId()))); + cacheManager.invalidateObject(true, Server.class, server.getId(), ObjectOperation.UPDATE); + LogAction.edit(getUserId(), server); + return Response.ok(server).build(); } @Path("geocode") @@ -157,4 +157,11 @@ public class ServerResource extends BaseResource { return Response.ok().build(); } + @Path("cache") + @GET + public String cache() throws StorageException { + permissionsService.checkAdmin(getUserId()); + return cacheManager.toString(); + } + } diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 99537f912..47ea9b07c 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -126,7 +126,7 @@ public class UserResource extends BaseObjectResource { @Path("{id}") @DELETE - public Response remove(@PathParam("id") long id) throws StorageException { + public Response remove(@PathParam("id") long id) throws Exception { Response response = super.remove(id); if (getUserId() == id) { request.getSession().removeAttribute(SessionResource.USER_ID_KEY); diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java index 1c4660320..01b212c60 100644 --- a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java @@ -69,10 +69,8 @@ public abstract class BaseBroadcastService implements BroadcastService { } @Override - public void invalidateObject( - boolean local, - Class clazz, long id, - ObjectOperation operation) { + public void invalidateObject( + boolean local, Class clazz, long id, ObjectOperation operation) { BroadcastMessage message = new BroadcastMessage(); var invalidateObject = new BroadcastMessage.InvalidateObject(); invalidateObject.setClazz(Permission.getKey(clazz)); @@ -83,11 +81,8 @@ public abstract class BaseBroadcastService implements BroadcastService { } @Override - public void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2, - boolean link) { + public synchronized void invalidatePermission( + boolean local, Class clazz1, long id1, Class clazz2, long id2, boolean link) { BroadcastMessage message = new BroadcastMessage(); var invalidatePermission = new BroadcastMessage.InvalidatePermission(); invalidatePermission.setClazz1(Permission.getKey(clazz1)); @@ -101,7 +96,7 @@ public abstract class BaseBroadcastService implements BroadcastService { protected abstract void sendMessage(BroadcastMessage message); - protected void handleMessage(BroadcastMessage message) { + protected void handleMessage(BroadcastMessage message) throws Exception { if (message.getDevice() != null) { listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); } else if (message.getPosition() != null) { @@ -112,17 +107,21 @@ public abstract class BaseBroadcastService implements BroadcastService { listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); } else if (message.getInvalidateObject() != null) { var invalidateObject = message.getInvalidateObject(); - listeners.forEach(listeners -> listeners.invalidateObject( - false, - Permission.getKeyClass(invalidateObject.getClazz()), invalidateObject.getId(), - invalidateObject.getOperation())); + for (BroadcastInterface listener : listeners) { + listener.invalidateObject( + false, + Permission.getKeyClass(invalidateObject.getClazz()), invalidateObject.getId(), + invalidateObject.getOperation()); + } } else if (message.getInvalidatePermission() != null) { var invalidatePermission = message.getInvalidatePermission(); - listeners.forEach(listener -> listener.invalidatePermission( - false, - Permission.getKeyClass(invalidatePermission.getClazz1()), invalidatePermission.getId1(), - Permission.getKeyClass(invalidatePermission.getClazz2()), invalidatePermission.getId2(), - invalidatePermission.getLink())); + for (BroadcastInterface listener : listeners) { + listener.invalidatePermission( + false, + Permission.getKeyClass(invalidatePermission.getClazz1()), invalidatePermission.getId1(), + Permission.getKeyClass(invalidatePermission.getClazz2()), invalidatePermission.getId2(), + invalidatePermission.getLink()); + } } } diff --git a/src/main/java/org/traccar/broadcast/BroadcastInterface.java b/src/main/java/org/traccar/broadcast/BroadcastInterface.java index 25fdf4d93..d0a491cd2 100644 --- a/src/main/java/org/traccar/broadcast/BroadcastInterface.java +++ b/src/main/java/org/traccar/broadcast/BroadcastInterface.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 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. @@ -35,16 +35,12 @@ public interface BroadcastInterface { default void updateCommand(boolean local, long deviceId) { } - default void invalidateObject( - boolean local, - Class clazz, long id, - ObjectOperation operation) { + default void invalidateObject( + boolean local, Class clazz, long id, ObjectOperation operation) throws Exception { } - default void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2, - boolean link) { + default void invalidatePermission( + boolean local, Class clazz1, long id1, Class clazz2, long id2, boolean link) throws Exception { } + } diff --git a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java index 1c02b319b..793c6df36 100644 --- a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java @@ -103,7 +103,7 @@ public class MulticastBroadcastService extends BaseBroadcastService { } publisherSocket = null; socket.leaveGroup(group, networkInterface); - } catch (IOException e) { + } catch (Exception e) { throw new RuntimeException(e); } } diff --git a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java index e87ad5e61..697c45a4a 100644 --- a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java @@ -38,7 +38,6 @@ public class RedisBroadcastService extends BaseBroadcastService { private final ExecutorService service = Executors.newSingleThreadExecutor(); - private final String url; private final String channel = "traccar"; private Jedis subscriber; @@ -48,7 +47,7 @@ public class RedisBroadcastService extends BaseBroadcastService { public RedisBroadcastService(Config config, ObjectMapper objectMapper) throws IOException { this.objectMapper = objectMapper; - url = config.getString(Keys.BROADCAST_ADDRESS); + String url = config.getString(Keys.BROADCAST_ADDRESS); try { subscriber = new Jedis(url); @@ -69,9 +68,7 @@ public class RedisBroadcastService extends BaseBroadcastService { try { String payload = id + ":" + objectMapper.writeValueAsString(message); publisher.publish(channel, payload); - } catch (IOException e) { - LOGGER.warn("Broadcast failed", e); - } catch (JedisConnectionException e) { + } catch (IOException | JedisConnectionException e) { LOGGER.warn("Broadcast failed", e); } } @@ -114,13 +111,11 @@ public class RedisBroadcastService extends BaseBroadcastService { if (messageChannel.equals(channel) && parts.length == 2 && !id.equals(parts[0])) { handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); } - } catch (IOException e) { + } catch (Exception e) { LOGGER.warn("Broadcast handleMessage failed", e); } } }, channel); - } catch (JedisConnectionException e) { - throw new RuntimeException(e); } catch (JedisException e) { throw new RuntimeException(e); } diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 79585d67a..45263ff3c 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -29,7 +29,6 @@ import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Maintenance; -import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.notification.MessageException; import org.traccar.notification.NotificatorManager; @@ -88,7 +87,7 @@ public class NotificationManager { return; } - var notifications = cacheManager.getDeviceObjects(event.getDeviceId(), Notification.class).stream() + var notifications = cacheManager.getDeviceNotifications(event.getDeviceId()) .filter(notification -> notification.getType().equals(event.getType())) .filter(notification -> { if (event.getType().equals(Event.TYPE_ALARM)) { @@ -162,7 +161,7 @@ public class NotificationManager { try { cacheManager.addDevice(event.getDeviceId()); updateEvent(event, position); - } catch (StorageException e) { + } catch (Exception e) { throw new RuntimeException(e); } finally { cacheManager.removeDevice(event.getDeviceId()); diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index a39683b2b..d75eb21a9 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -24,7 +24,6 @@ import com.google.firebase.messaging.AndroidNotification; import com.google.firebase.messaging.ApnsConfig; import com.google.firebase.messaging.Aps; import com.google.firebase.messaging.FirebaseMessaging; -import com.google.firebase.messaging.FirebaseMessagingException; import com.google.firebase.messaging.MessagingErrorCode; import com.google.firebase.messaging.MulticastMessage; import org.slf4j.Logger; @@ -40,7 +39,6 @@ import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; import org.traccar.session.cache.CacheManager; import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; @@ -136,9 +134,9 @@ public class NotificatorFirebase implements Notificator { storage.updateObject(user, new Request( new Columns.Include("attributes"), new Condition.Equals("id", user.getId()))); - cacheManager.updateOrInvalidate(true, user, ObjectOperation.UPDATE); + cacheManager.invalidateObject(true, User.class, user.getId(), ObjectOperation.UPDATE); } - } catch (FirebaseMessagingException | StorageException e) { + } catch (Exception e) { LOGGER.warn("Firebase error", e); } } diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index 82e1584a5..717742a1e 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java @@ -27,7 +27,6 @@ import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; import org.traccar.session.cache.CacheManager; import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; @@ -129,9 +128,9 @@ public class NotificatorTraccar implements Notificator { storage.updateObject(user, new Request( new Columns.Include("attributes"), new Condition.Equals("id", user.getId()))); - cacheManager.updateOrInvalidate(true, user, ObjectOperation.UPDATE); + cacheManager.invalidateObject(true, User.class, user.getId(), ObjectOperation.UPDATE); } - } catch (StorageException e) { + } catch (Exception e) { LOGGER.warn("Push error", e); } } diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 0b13a5a72..3716fdf9a 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -102,7 +102,7 @@ public class ConnectionManager implements BroadcastInterface { public DeviceSession getDeviceSession( Protocol protocol, Channel channel, SocketAddress remoteAddress, - String... uniqueIds) throws StorageException { + String... uniqueIds) throws Exception { Endpoint endpoint = new Endpoint(channel, remoteAddress); Map endpointSessions = sessionsByEndpoint.getOrDefault( @@ -327,11 +327,8 @@ public class ConnectionManager implements BroadcastInterface { } @Override - public synchronized void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2, - boolean link) { + public synchronized void invalidatePermission( + boolean local, Class clazz1, long id1, Class clazz2, long id2, boolean link) { if (link && clazz1.equals(User.class) && clazz2.equals(Device.class)) { if (listeners.containsKey(id1)) { userDevices.get(id1).add(id2); diff --git a/src/main/java/org/traccar/session/cache/CacheGraph.java b/src/main/java/org/traccar/session/cache/CacheGraph.java new file mode 100644 index 000000000..c99997288 --- /dev/null +++ b/src/main/java/org/traccar/session/cache/CacheGraph.java @@ -0,0 +1,139 @@ +/* + * 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.session.cache; + +import org.traccar.model.BaseModel; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public class CacheGraph { + + private final Map roots = new HashMap<>(); + private final WeakValueMap nodes = new WeakValueMap<>(); + + void addObject(BaseModel value) { + CacheKey key = new CacheKey(value); + CacheNode node = new CacheNode(value); + roots.put(key, node); + nodes.put(key, node); + } + + void removeObject(Class clazz, long id) { + CacheKey key = new CacheKey(clazz, id); + CacheNode node = nodes.remove(key); + if (node != null) { + node.getAllLinks(false).forEach(child -> child.getLinks(key.getClazz(), true).remove(node)); + } + roots.remove(key); + } + + @SuppressWarnings("unchecked") + T getObject(Class clazz, long id) { + CacheNode node = nodes.get(new CacheKey(clazz, id)); + return node != null ? (T) node.getValue() : null; + } + + Stream getObjects( + Class fromClass, long fromId, + Class clazz, Set> proxies, boolean forward) { + + CacheNode rootNode = nodes.get(new CacheKey(fromClass, fromId)); + if (rootNode != null) { + return getObjectStream(rootNode, clazz, proxies, forward); + } else { + return Stream.empty(); + } + } + + @SuppressWarnings("unchecked") + private Stream getObjectStream( + CacheNode rootNode, Class clazz, Set> proxies, boolean forward) { + + if (proxies.contains(clazz)) { + return Stream.empty(); + } + + var directSteam = rootNode.getLinks(clazz, forward).stream() + .map(node -> (T) node.getValue()); + + var proxyStream = proxies.stream() + .flatMap(proxyClass -> rootNode.getLinks(proxyClass, forward).stream() + .flatMap(node -> getObjectStream(node, clazz, proxies, forward))); + + return Stream.concat(directSteam, proxyStream); + } + + void updateObject(BaseModel value) { + CacheNode node = nodes.get(new CacheKey(value)); + if (node != null) { + node.setValue(value); + } + } + + boolean addLink( + Class fromClazz, long fromId, + BaseModel toValue) { + boolean stop = true; + CacheNode fromNode = nodes.get(new CacheKey(fromClazz, fromId)); + if (fromNode != null) { + CacheKey toKey = new CacheKey(toValue); + CacheNode toNode = nodes.get(toKey); + if (toNode == null) { + stop = false; + toNode = new CacheNode(toValue); + nodes.put(toKey, toNode); + } + fromNode.getLinks(toValue.getClass(), true).add(toNode); + toNode.getLinks(fromClazz, false).add(fromNode); + } + return stop; + } + + void removeLink( + Class fromClazz, long fromId, + Class toClazz, long toId) { + CacheNode fromNode = nodes.get(new CacheKey(fromClazz, fromId)); + if (fromNode != null) { + CacheNode toNode = nodes.get(new CacheKey(toClazz, toId)); + if (toNode != null) { + fromNode.getLinks(toClazz, true).remove(toNode); + toNode.getLinks(fromClazz, false).remove(fromNode); + } + } + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + for (CacheNode node : roots.values()) { + printNode(stringBuilder, node, ""); + } + return stringBuilder.toString().trim(); + } + + private void printNode(StringBuilder stringBuilder, CacheNode node, String indentation) { + stringBuilder + .append('\n') + .append(indentation) + .append(node.getValue().getClass().getSimpleName()) + .append('(').append(node.getValue().getId()).append(')'); + node.getAllLinks(true).forEach(child -> printNode(stringBuilder, child, indentation + " ")); + } + +} diff --git a/src/main/java/org/traccar/session/cache/CacheKey.java b/src/main/java/org/traccar/session/cache/CacheKey.java index 23145e34b..f27d5fbf5 100644 --- a/src/main/java/org/traccar/session/cache/CacheKey.java +++ b/src/main/java/org/traccar/session/cache/CacheKey.java @@ -33,6 +33,10 @@ class CacheKey { this.id = id; } + public Class getClazz() { + return clazz; + } + public boolean classIs(Class clazz) { return clazz.equals(this.clazz); } diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index dc9c86ef3..918c97c66 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -15,11 +15,10 @@ */ package org.traccar.session.cache; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.traccar.broadcast.BroadcastInterface; import org.traccar.broadcast.BroadcastService; -import org.traccar.model.ObjectOperation; import org.traccar.config.Config; import org.traccar.model.Attribute; import org.traccar.model.BaseModel; @@ -31,6 +30,8 @@ import org.traccar.model.Group; import org.traccar.model.GroupedModel; import org.traccar.model.Maintenance; import org.traccar.model.Notification; +import org.traccar.model.ObjectOperation; +import org.traccar.model.Permission; import org.traccar.model.Position; import org.traccar.model.Schedulable; import org.traccar.model.Server; @@ -41,30 +42,20 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; +import java.util.stream.Stream; @Singleton public class CacheManager implements BroadcastInterface { - private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class); - private static final int GROUP_DEPTH_LIMIT = 3; - private static final Collection> CLASSES = Arrays.asList( - Attribute.class, Driver.class, Geofence.class, Maintenance.class, Notification.class); + private static final Set> GROUPED_CLASSES = + Set.of(Attribute.class, Driver.class, Geofence.class, Maintenance.class, Notification.class); private final Config config; private final Storage storage; @@ -72,24 +63,26 @@ public class CacheManager implements BroadcastInterface { private final ReadWriteLock lock = new ReentrantReadWriteLock(); - private final Map deviceCache = new HashMap<>(); - private final Map deviceReferences = new HashMap<>(); - private final Map, Set>> deviceLinks = new HashMap<>(); - private final Map devicePositions = new HashMap<>(); + private final CacheGraph graph = new CacheGraph(); private Server server; - private final Map> notificationUsers = new HashMap<>(); + private final Map devicePositions = new HashMap<>(); + private final Map deviceReferences = new HashMap<>(); @Inject public CacheManager(Config config, Storage storage, BroadcastService broadcastService) throws StorageException { this.config = config; this.storage = storage; this.broadcastService = broadcastService; - invalidateServer(); - invalidateUsers(); + server = storage.getObject(Server.class, new Request(new Columns.All())); broadcastService.registerListener(this); } + @Override + public String toString() { + return graph.toString(); + } + public Config getConfig() { return config; } @@ -97,29 +90,17 @@ public class CacheManager implements BroadcastInterface { public T getObject(Class clazz, long id) { try { lock.readLock().lock(); - var cacheValue = deviceCache.get(new CacheKey(clazz, id)); - return cacheValue != null ? cacheValue.getValue() : null; + return graph.getObject(clazz, id); } finally { lock.readLock().unlock(); } } - public List getDeviceObjects(long deviceId, Class clazz) { + public Set getDeviceObjects(long deviceId, Class clazz) { try { lock.readLock().lock(); - var links = deviceLinks.get(deviceId); - if (links != null) { - return links.getOrDefault(clazz, new LinkedHashSet<>()).stream() - .map(id -> { - var cacheValue = deviceCache.get(new CacheKey(clazz, id)); - return cacheValue != null ? cacheValue.getValue() : null; - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } else { - LOGGER.warn("Device {} cache missing", deviceId); - return Collections.emptyList(); - } + return graph.getObjects(Device.class, deviceId, clazz, Set.of(Group.class), true) + .collect(Collectors.toUnmodifiableSet()); } finally { lock.readLock().unlock(); } @@ -143,30 +124,40 @@ public class CacheManager implements BroadcastInterface { } } - public List getNotificationUsers(long notificationId, long deviceId) { + public Set getNotificationUsers(long notificationId, long deviceId) { + try { + lock.readLock().lock(); + Set deviceUsers = getDeviceObjects(deviceId, User.class); + return graph.getObjects(Notification.class, notificationId, User.class, Set.of(), false) + .filter(deviceUsers::contains) + .collect(Collectors.toUnmodifiableSet()); + } finally { + lock.readLock().unlock(); + } + } + + public Stream getDeviceNotifications(long deviceId) { try { lock.readLock().lock(); - var users = deviceLinks.get(deviceId).get(User.class).stream() + var direct = graph.getObjects(Device.class, deviceId, Notification.class, Set.of(Group.class), true) + .map(BaseModel::getId) .collect(Collectors.toUnmodifiableSet()); - return notificationUsers.getOrDefault(notificationId, new LinkedList<>()).stream() - .filter(user -> users.contains(user.getId())) - .collect(Collectors.toUnmodifiableList()); + return graph.getObjects(Device.class, deviceId, Notification.class, Set.of(Group.class, User.class), true) + .filter(notification -> notification.getAlways() || direct.contains(notification.getId())); } finally { lock.readLock().unlock(); } } - public void addDevice(long deviceId) throws StorageException { + public void addDevice(long deviceId) throws Exception { try { lock.writeLock().lock(); - Integer references = deviceReferences.get(deviceId); - if (references != null) { - references += 1; - } else { - unsafeAddDevice(deviceId); - references = 1; + if (deviceReferences.computeIfAbsent(deviceId, k -> new AtomicInteger()).getAndIncrement() <= 0) { + Device device = storage.getObject(Device.class, new Request( + new Columns.All(), new Condition.Equals("id", deviceId))); + graph.addObject(device); + initializeCache(device); } - deviceReferences.put(deviceId, references); } finally { lock.writeLock().unlock(); } @@ -175,15 +166,10 @@ public class CacheManager implements BroadcastInterface { public void removeDevice(long deviceId) { try { lock.writeLock().lock(); - Integer references = deviceReferences.get(deviceId); - if (references != null) { - references -= 1; - if (references <= 0) { - unsafeRemoveDevice(deviceId); - deviceReferences.remove(deviceId); - } else { - deviceReferences.put(deviceId, references); - } + if (deviceReferences.computeIfAbsent(deviceId, k -> new AtomicInteger()).incrementAndGet() <= 0) { + graph.removeObject(Device.class, deviceId); + devicePositions.remove(deviceId); + deviceReferences.remove(deviceId); } } finally { lock.writeLock().unlock(); @@ -193,7 +179,7 @@ public class CacheManager implements BroadcastInterface { public void updatePosition(Position position) { try { lock.writeLock().lock(); - if (deviceLinks.containsKey(position.getDeviceId())) { + if (deviceReferences.containsKey(position.getDeviceId())) { devicePositions.put(position.getDeviceId(), position); } } finally { @@ -202,226 +188,140 @@ public class CacheManager implements BroadcastInterface { } @Override - public void invalidateObject( - boolean local, - Class clazz, long id, - ObjectOperation operation) { - try { - var object = storage.getObject(clazz, new Request( - new Columns.All(), new Condition.Equals("id", id))); - if (object != null) { - updateOrInvalidate(local, object, operation); - } else { - invalidate(clazz, id); - } - } catch (StorageException e) { - throw new RuntimeException(e); - } - } - - public void updateOrInvalidate( - boolean local, T object, ObjectOperation operation) throws StorageException { + public void invalidateObject( + boolean local, Class clazz, long id, ObjectOperation operation) throws Exception { if (local) { - broadcastService.invalidateObject(true, object.getClass(), object.getId(), operation); + broadcastService.invalidateObject(true, clazz, id, operation); } - if (object instanceof Server) { - invalidateServer(); + if (operation == ObjectOperation.DELETE) { + graph.removeObject(clazz, id); + } + if (operation != ObjectOperation.UPDATE) { return; } - if (object instanceof User) { - invalidateUsers(); + + if (clazz.equals(Server.class)) { + server = storage.getObject(Server.class, new Request(new Columns.All())); return; } - boolean invalidate = false; - var before = getObject(object.getClass(), object.getId()); + var after = storage.getObject(clazz, new Request(new Columns.All(), new Condition.Equals("id", id))); + if (after == null) { + return; + } + var before = getObject(after.getClass(), after.getId()); if (before == null) { return; - } else if (object instanceof GroupedModel) { - if (((GroupedModel) before).getGroupId() != ((GroupedModel) object).getGroupId()) { - invalidate = true; - } - } else if (object instanceof Schedulable) { - if (((Schedulable) before).getCalendarId() != ((Schedulable) object).getCalendarId()) { - invalidate = true; - } } - if (invalidate) { - invalidate(object.getClass(), object.getId()); - } else { - try { - lock.writeLock().lock(); - deviceCache.get(new CacheKey(object.getClass(), object.getId())).setValue(object); - } finally { - lock.writeLock().unlock(); + + if (after instanceof GroupedModel) { + long beforeGroupId = ((GroupedModel) before).getGroupId(); + long afterGroupId = ((GroupedModel) after).getGroupId(); + if (beforeGroupId != afterGroupId) { + if (beforeGroupId > 0) { + invalidatePermission(clazz, id, Group.class, beforeGroupId, false); + } + if (afterGroupId > 0) { + invalidatePermission(clazz, id, Group.class, afterGroupId, true); + } } + } else if (after instanceof Schedulable) { + long beforeCalendarId = ((Schedulable) before).getCalendarId(); + long afterCalendarId = ((Schedulable) after).getCalendarId(); + if (beforeCalendarId != afterCalendarId) { + if (beforeCalendarId > 0) { + invalidatePermission(clazz, id, Calendar.class, beforeCalendarId, false); + } + if (afterCalendarId > 0) { + invalidatePermission(clazz, id, Calendar.class, afterCalendarId, true); + } + } + // TODO handle notification always change } - } - public void invalidate(Class clazz, long id) throws StorageException { - invalidate(new CacheKey(clazz, id)); + graph.updateObject(after); } @Override - public void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2, - boolean link) { + public void invalidatePermission( + boolean local, Class clazz1, long id1, Class clazz2, long id2, boolean link) throws Exception { if (local) { broadcastService.invalidatePermission(true, clazz1, id1, clazz2, id2, link); } - try { - invalidate(new CacheKey(clazz1, id1), new CacheKey(clazz2, id2)); - } catch (StorageException e) { - throw new RuntimeException(e); + if (clazz1.equals(User.class) && GroupedModel.class.isAssignableFrom(clazz2)) { + invalidatePermission(clazz2, id2, clazz1, id1, link); + } else { + invalidatePermission(clazz1, id1, clazz2, id2, link); } } - private void invalidateServer() throws StorageException { - server = storage.getObject(Server.class, new Request(new Columns.All())); - } + private void invalidatePermission( + Class fromClass, long fromId, Class toClass, long toId, boolean link) throws Exception { - private void invalidateUsers() throws StorageException { - notificationUsers.clear(); - Map users = new HashMap<>(); - storage.getObjects(User.class, new Request(new Columns.All())) - .forEach(user -> users.put(user.getId(), user)); - storage.getPermissions(User.class, Notification.class).forEach(permission -> { - long notificationId = permission.getPropertyId(); - var user = users.get(permission.getOwnerId()); - notificationUsers.computeIfAbsent(notificationId, k -> new LinkedList<>()).add(user); - }); - } + boolean groupLink = GroupedModel.class.isAssignableFrom(fromClass) && toClass.equals(Group.class); + boolean calendarLink = Schedulable.class.isAssignableFrom(fromClass) && toClass.equals(Calendar.class); + boolean userLink = fromClass.equals(User.class) && toClass.equals(Notification.class); - private void addObject(long deviceId, BaseModel object) { - deviceCache.computeIfAbsent(new CacheKey(object), k -> new CacheValue(object)).retain(deviceId); - } + boolean groupedLinks = GroupedModel.class.isAssignableFrom(fromClass) + && (GROUPED_CLASSES.contains(toClass) || toClass.equals(User.class)); - private void unsafeAddDevice(long deviceId) throws StorageException { - Map, Set> links = new HashMap<>(); - - Device device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", deviceId))); - if (device != null) { - addObject(deviceId, device); - if (device.getCalendarId() > 0) { - var calendar = storage.getObject(Calendar.class, new Request( - new Columns.All(), new Condition.Equals("id", device.getCalendarId()))); - links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId()); - addObject(deviceId, calendar); - } + if (!groupLink && !calendarLink && !userLink && !groupedLinks) { + return; + } - int groupDepth = 0; - long groupId = device.getGroupId(); - while (groupDepth < GROUP_DEPTH_LIMIT && groupId > 0) { - Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", groupId))); - links.computeIfAbsent(Group.class, k -> new LinkedHashSet<>()).add(group.getId()); - addObject(deviceId, group); - groupId = group.getGroupId(); - groupDepth += 1; + if (link) { + BaseModel object = storage.getObject(toClass, new Request( + new Columns.All(), new Condition.Equals("id", toId))); + if (!graph.addLink(fromClass, fromId, object)) { + initializeCache(object); } + } else { + graph.removeLink(fromClass, fromId, toClass, toId); + } + } - for (Class clazz : CLASSES) { - var objects = storage.getObjects(clazz, new Request( - new Columns.All(), new Condition.Permission(Device.class, deviceId, clazz))); - links.put(clazz, objects.stream().map(BaseModel::getId).collect(Collectors.toSet())); - for (var object : objects) { - addObject(deviceId, object); - if (object instanceof Schedulable) { - var scheduled = (Schedulable) object; - if (scheduled.getCalendarId() > 0) { - var calendar = storage.getObject(Calendar.class, new Request( - new Columns.All(), new Condition.Equals("id", scheduled.getCalendarId()))); - links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId()); - addObject(deviceId, calendar); - } - } + private void initializeCache(BaseModel object) throws Exception { + if (object instanceof User) { + for (Permission permission : storage.getPermissions(User.class, Notification.class)) { + if (permission.getOwnerId() == object.getId()) { + invalidatePermission( + permission.getOwnerClass(), permission.getOwnerId(), + permission.getPropertyClass(), permission.getPropertyId(), true); } } + } else { + if (object instanceof GroupedModel) { + long groupId = ((GroupedModel) object).getGroupId(); + if (groupId > 0) { + invalidatePermission(object.getClass(), object.getId(), Group.class, groupId, true); + } - var users = storage.getObjects(User.class, new Request( - new Columns.All(), new Condition.Permission(User.class, Device.class, deviceId))); - links.put(User.class, users.stream().map(BaseModel::getId).collect(Collectors.toSet())); - for (var user : users) { - addObject(deviceId, user); - var notifications = storage.getObjects(Notification.class, new Request( - new Columns.All(), - new Condition.Permission(User.class, user.getId(), Notification.class))).stream() - .filter(Notification::getAlways) - .collect(Collectors.toList()); - for (var notification : notifications) { - links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()).add(notification.getId()); - addObject(deviceId, notification); - if (notification.getCalendarId() > 0) { - var calendar = storage.getObject(Calendar.class, new Request( - new Columns.All(), new Condition.Equals("id", notification.getCalendarId()))); - links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId()); - addObject(deviceId, calendar); + for (Permission permission : storage.getPermissions(User.class, object.getClass())) { + if (permission.getPropertyId() == object.getId()) { + invalidatePermission( + object.getClass(), object.getId(), User.class, permission.getOwnerId(), true); } } - } - - deviceLinks.put(deviceId, links); - if (device.getPositionId() > 0) { - devicePositions.put(deviceId, storage.getObject(Position.class, new Request( - new Columns.All(), new Condition.Equals("id", device.getPositionId())))); + for (Class clazz : GROUPED_CLASSES) { + for (Permission permission : storage.getPermissions(object.getClass(), clazz)) { + if (permission.getOwnerId() == object.getId()) { + invalidatePermission( + object.getClass(), object.getId(), clazz, permission.getPropertyId(), true); + } + } + } } - } - } - private void unsafeRemoveDevice(long deviceId) { - deviceCache.remove(new CacheKey(Device.class, deviceId)); - deviceLinks.remove(deviceId).forEach((clazz, ids) -> ids.forEach(id -> { - var key = new CacheKey(clazz, id); - deviceCache.computeIfPresent(key, (k, value) -> { - value.release(deviceId); - return value.getReferences().isEmpty() ? null : value; - }); - })); - devicePositions.remove(deviceId); - } - - private void invalidate(CacheKey... keys) throws StorageException { - try { - lock.writeLock().lock(); - unsafeInvalidate(keys); - } finally { - lock.writeLock().unlock(); - } - } - - private void unsafeInvalidate(CacheKey[] keys) throws StorageException { - boolean invalidateServer = false; - boolean invalidateUsers = false; - Set linkedDevices = new HashSet<>(); - for (var key : keys) { - if (key.classIs(Server.class)) { - invalidateServer = true; - } else { - if (key.classIs(User.class) || key.classIs(Notification.class)) { - invalidateUsers = true; + if (object instanceof Schedulable) { + long calendarId = ((Schedulable) object).getCalendarId(); + if (calendarId > 0) { + invalidatePermission(object.getClass(), object.getId(), Calendar.class, calendarId, true); } - deviceCache.computeIfPresent(key, (k, value) -> { - linkedDevices.addAll(value.getReferences()); - return value; - }); } } - for (long deviceId : linkedDevices) { - unsafeRemoveDevice(deviceId); - unsafeAddDevice(deviceId); - } - if (invalidateServer) { - invalidateServer(); - } - if (invalidateUsers) { - invalidateUsers(); - } } } diff --git a/src/main/java/org/traccar/session/cache/CacheNode.java b/src/main/java/org/traccar/session/cache/CacheNode.java new file mode 100644 index 000000000..7b584f81a --- /dev/null +++ b/src/main/java/org/traccar/session/cache/CacheNode.java @@ -0,0 +1,40 @@ +package org.traccar.session.cache; + +import org.traccar.model.BaseModel; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public class CacheNode { + + private BaseModel value; + + private final Map, Set> links = new HashMap<>(); + private final Map, Set> backlinks = new HashMap<>(); + + public CacheNode(BaseModel value) { + this.value = value; + } + + public BaseModel getValue() { + return value; + } + + public void setValue(BaseModel value) { + this.value = value; + } + + public Set getLinks(Class clazz, boolean forward) { + var map = forward ? links : backlinks; + return map.computeIfAbsent(clazz, k -> new HashSet<>()); + } + + public Stream getAllLinks(boolean forward) { + var map = forward ? links : backlinks; + return map.values().stream().flatMap(Set::stream); + } + +} diff --git a/src/main/java/org/traccar/session/cache/CacheValue.java b/src/main/java/org/traccar/session/cache/CacheValue.java deleted file mode 100644 index 1f0383ce5..000000000 --- a/src/main/java/org/traccar/session/cache/CacheValue.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2022 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.session.cache; - -import org.traccar.model.BaseModel; - -import java.util.HashSet; -import java.util.Set; - -class CacheValue { - - private BaseModel value; - private final Set references = new HashSet<>(); - - CacheValue(BaseModel value) { - this.value = value; - } - - public void retain(long deviceId) { - references.add(deviceId); - } - - public void release(long deviceId) { - references.remove(deviceId); - } - - @SuppressWarnings("unchecked") - public T getValue() { - return (T) value; - } - - public void setValue(BaseModel value) { - this.value = value; - } - - public Set getReferences() { - return references; - } - -} diff --git a/src/main/java/org/traccar/session/cache/WeakValueMap.java b/src/main/java/org/traccar/session/cache/WeakValueMap.java new file mode 100644 index 000000000..8323e2c30 --- /dev/null +++ b/src/main/java/org/traccar/session/cache/WeakValueMap.java @@ -0,0 +1,44 @@ +/* + * 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.session.cache; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; + +public class WeakValueMap { + + private final Map> map = new HashMap<>(); + + public void put(K key, V value) { + map.put(key, new WeakReference<>(value)); + } + + public V get(K key) { + WeakReference weakReference = map.get(key); + return (weakReference != null) ? weakReference.get() : null; + } + + public V remove(K key) { + WeakReference weakReference = map.remove(key); + return (weakReference != null) ? weakReference.get() : null; + } + + private void clean() { + map.entrySet().removeIf(entry -> entry.getValue().get() == null); + } + +} diff --git a/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java index 5320be926..661336d76 100644 --- a/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java @@ -6,14 +6,15 @@ import org.traccar.model.Maintenance; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import java.util.Arrays; import java.util.Date; +import java.util.Set; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.anyLong; public class MaintenanceEventHandlerTest extends BaseTest { @@ -29,7 +30,7 @@ public class MaintenanceEventHandlerTest extends BaseTest { var maintenance = mock(Maintenance.class); when(maintenance.getType()).thenReturn(Position.KEY_TOTAL_DISTANCE); - var maintenances = Arrays.asList(maintenance); + var maintenances = Set.of(maintenance); var cacheManager = mock(CacheManager.class); when(cacheManager.getDeviceObjects(anyLong(), eq(Maintenance.class))).thenReturn(maintenances); @@ -48,12 +49,12 @@ public class MaintenanceEventHandlerTest extends BaseTest { assertTrue(eventHandler.analyzePosition(position).isEmpty()); lastPosition.set(Position.KEY_TOTAL_DISTANCE, 9999); - position.set(Position.KEY_TOTAL_DISTANCE, 10001); - assertTrue(eventHandler.analyzePosition(position).size() == 1); + position.set(Position.KEY_TOTAL_DISTANCE, 10001); + assertEquals(1, eventHandler.analyzePosition(position).size()); lastPosition.set(Position.KEY_TOTAL_DISTANCE, 11999); - position.set(Position.KEY_TOTAL_DISTANCE, 12001); - assertTrue(eventHandler.analyzePosition(position).size() == 1); + position.set(Position.KEY_TOTAL_DISTANCE, 12001); + assertEquals(1, eventHandler.analyzePosition(position).size()); } -- cgit v1.2.3 From 5cebbfccae29dad81d89591a798d6aa29dd42b75 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 23 Dec 2023 07:02:22 -0800 Subject: Initialize position cache --- src/main/java/org/traccar/session/cache/CacheManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 918c97c66..bb9b4c995 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -157,6 +157,10 @@ public class CacheManager implements BroadcastInterface { new Columns.All(), new Condition.Equals("id", deviceId))); graph.addObject(device); initializeCache(device); + if (device.getPositionId() > 0) { + devicePositions.put(deviceId, storage.getObject(Position.class, new Request( + new Columns.All(), new Condition.Equals("id", device.getPositionId())))); + } } } finally { lock.writeLock().unlock(); -- cgit v1.2.3 From f37734db8425e5a1c660d554a6f3bf56af1c2bca Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 27 Dec 2023 18:02:18 -0800 Subject: Option to observe data logs --- src/main/java/org/traccar/BasePipelineFactory.java | 6 +- src/main/java/org/traccar/api/AsyncSocket.java | 40 ++++++++++---- .../traccar/handler/StandardLoggingHandler.java | 64 ++++++++++++---------- src/main/java/org/traccar/model/LogRecord.java | 63 +++++++++++++++++++++ .../org/traccar/session/ConnectionManager.java | 34 ++++++++---- src/main/java/org/traccar/session/Endpoint.java | 58 -------------------- 6 files changed, 152 insertions(+), 113 deletions(-) create mode 100644 src/main/java/org/traccar/model/LogRecord.java delete mode 100644 src/main/java/org/traccar/session/Endpoint.java diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index 5b48f3d15..ca4a4ae63 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -124,7 +124,11 @@ public abstract class BasePipelineFactory extends ChannelInitializer { pipeline.addLast(handler); } pipeline.addLast(new NetworkMessageHandler()); - pipeline.addLast(new StandardLoggingHandler(protocol)); + + var loggingHandler = new StandardLoggingHandler(protocol); + injector.injectMembers(loggingHandler); + pipeline.addLast(loggingHandler); + if (!connector.isDatagram() && !config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) { pipeline.addLast(new AcknowledgementHandler()); } diff --git a/src/main/java/org/traccar/api/AsyncSocket.java b/src/main/java/org/traccar/api/AsyncSocket.java index 5fc4b4412..f5fbcbf62 100644 --- a/src/main/java/org/traccar/api/AsyncSocket.java +++ b/src/main/java/org/traccar/api/AsyncSocket.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -22,16 +22,17 @@ import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.helper.model.PositionUtil; -import org.traccar.session.ConnectionManager; import org.traccar.model.Device; import org.traccar.model.Event; +import org.traccar.model.LogRecord; import org.traccar.model.Position; +import org.traccar.session.ConnectionManager; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.UpdateListener { @@ -41,12 +42,15 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U private static final String KEY_DEVICES = "devices"; private static final String KEY_POSITIONS = "positions"; private static final String KEY_EVENTS = "events"; + private static final String KEY_LOGS = "logs"; private final ObjectMapper objectMapper; private final ConnectionManager connectionManager; private final Storage storage; private final long userId; + private boolean includeLogs; + public AsyncSocket(ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage, long userId) { this.objectMapper = objectMapper; this.connectionManager = connectionManager; @@ -75,6 +79,17 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U connectionManager.removeListener(userId, this); } + @Override + public void onWebSocketText(String message) { + super.onWebSocketText(message); + + try { + includeLogs = objectMapper.readTree(message).get("logs").asBoolean(); + } catch (JsonProcessingException e) { + LOGGER.warn("Socket JSON parsing error", e); + } + } + @Override public void onKeepalive() { sendData(new HashMap<>()); @@ -82,23 +97,24 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U @Override public void onUpdateDevice(Device device) { - Map> data = new HashMap<>(); - data.put(KEY_DEVICES, Collections.singletonList(device)); - sendData(data); + sendData(Map.of(KEY_DEVICES, List.of(device))); } @Override public void onUpdatePosition(Position position) { - Map> data = new HashMap<>(); - data.put(KEY_POSITIONS, Collections.singletonList(position)); - sendData(data); + sendData(Map.of(KEY_POSITIONS, List.of(position))); } @Override public void onUpdateEvent(Event event) { - Map> data = new HashMap<>(); - data.put(KEY_EVENTS, Collections.singletonList(event)); - sendData(data); + sendData(Map.of(KEY_EVENTS, List.of(event))); + } + + @Override + public void onUpdateLog(LogRecord record) { + if (includeLogs) { + sendData(Map.of(KEY_LOGS, List.of(record))); + } } private void sendData(Map> data) { diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java index 84492e2a5..b495747d3 100644 --- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java +++ b/src/main/java/org/traccar/handler/StandardLoggingHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -20,68 +20,72 @@ import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.NetworkMessage; import org.traccar.helper.NetworkUtil; +import org.traccar.model.LogRecord; +import org.traccar.session.ConnectionManager; import java.net.InetSocketAddress; -import java.net.SocketAddress; public class StandardLoggingHandler extends ChannelDuplexHandler { private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class); private final String protocol; + private ConnectionManager connectionManager; public StandardLoggingHandler(String protocol) { this.protocol = protocol; } + @Inject + public void setConnectionManager(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + } + @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - log(ctx, false, msg); + LogRecord record = createLogRecord(msg); + log(ctx, false, record); super.channelRead(ctx, msg); + if (record != null) { + connectionManager.updateLog(record); + } } @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - log(ctx, true, msg); + log(ctx, true, createLogRecord(msg)); super.write(ctx, msg, promise); } - public void log(ChannelHandlerContext ctx, boolean downstream, Object o) { - if (o instanceof NetworkMessage) { - NetworkMessage networkMessage = (NetworkMessage) o; + private LogRecord createLogRecord(Object msg) { + if (msg instanceof NetworkMessage) { + NetworkMessage networkMessage = (NetworkMessage) msg; if (networkMessage.getMessage() instanceof ByteBuf) { - log(ctx, downstream, networkMessage.getRemoteAddress(), (ByteBuf) networkMessage.getMessage()); + LogRecord record = new LogRecord(); + record.setAddress((InetSocketAddress) networkMessage.getRemoteAddress()); + record.setData(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage())); + return record; } - } else if (o instanceof ByteBuf) { - log(ctx, downstream, ctx.channel().remoteAddress(), (ByteBuf) o); } + return null; } - public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) { - StringBuilder message = new StringBuilder(); - - message.append("[").append(NetworkUtil.session(ctx.channel())).append(": "); - message.append(protocol); - if (downstream) { - message.append(" > "); - } else { - message.append(" < "); + private void log(ChannelHandlerContext ctx, boolean downstream, LogRecord record) { + if (record != null) { + StringBuilder message = new StringBuilder(); + message.append("[").append(NetworkUtil.session(ctx.channel())).append(": "); + message.append(protocol); + message.append(downstream ? " > " : " < "); + message.append(record.getAddress().getHostString()); + message.append("] "); + message.append(record.getData()); + LOGGER.info(message.toString()); } - - if (remoteAddress instanceof InetSocketAddress) { - message.append(((InetSocketAddress) remoteAddress).getHostString()); - } else { - message.append("unknown"); - } - message.append("] "); - - message.append(ByteBufUtil.hexDump(buf)); - - LOGGER.info(message.toString()); } } diff --git a/src/main/java/org/traccar/model/LogRecord.java b/src/main/java/org/traccar/model/LogRecord.java new file mode 100644 index 000000000..3feaadec2 --- /dev/null +++ b/src/main/java/org/traccar/model/LogRecord.java @@ -0,0 +1,63 @@ +/* + * 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.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.net.InetSocketAddress; + +public class LogRecord { + + private InetSocketAddress address; + + public void setAddress(InetSocketAddress address) { + this.address = address; + } + + @JsonIgnore + public InetSocketAddress getAddress() { + return address; + } + + public int getPort() { + return address.getPort(); + } + + public String getHost() { + return address.getHostString(); + } + + private String uniqueId; + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + private String data; + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + +} diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 3716fdf9a..7541cedfb 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -30,6 +30,7 @@ import org.traccar.database.NotificationManager; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Event; +import org.traccar.model.LogRecord; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.session.cache.CacheManager; @@ -64,7 +65,7 @@ public class ConnectionManager implements BroadcastInterface { private final long deviceTimeout; private final Map sessionsByDeviceId = new ConcurrentHashMap<>(); - private final Map> sessionsByEndpoint = new ConcurrentHashMap<>(); + private final Map> sessionsByEndpoint = new ConcurrentHashMap<>(); private final Config config; private final CacheManager cacheManager; @@ -104,9 +105,8 @@ public class ConnectionManager implements BroadcastInterface { Protocol protocol, Channel channel, SocketAddress remoteAddress, String... uniqueIds) throws Exception { - Endpoint endpoint = new Endpoint(channel, remoteAddress); Map endpointSessions = sessionsByEndpoint.getOrDefault( - endpoint, new ConcurrentHashMap<>()); + remoteAddress, new ConcurrentHashMap<>()); uniqueIds = Arrays.stream(uniqueIds).filter(Objects::nonNull).toArray(String[]::new); if (uniqueIds.length > 0) { @@ -133,19 +133,18 @@ public class ConnectionManager implements BroadcastInterface { DeviceSession oldSession = sessionsByDeviceId.remove(device.getId()); if (oldSession != null) { - Endpoint oldEndpoint = new Endpoint(oldSession.getChannel(), oldSession.getRemoteAddress()); - Map oldEndpointSessions = sessionsByEndpoint.get(oldEndpoint); + Map oldEndpointSessions = sessionsByEndpoint.get(oldSession.getRemoteAddress()); if (oldEndpointSessions != null && oldEndpointSessions.size() > 1) { oldEndpointSessions.remove(device.getUniqueId()); } else { - sessionsByEndpoint.remove(oldEndpoint); + sessionsByEndpoint.remove(oldSession.getRemoteAddress()); } } DeviceSession deviceSession = new DeviceSession( device.getId(), device.getUniqueId(), protocol, channel, remoteAddress); endpointSessions.put(device.getUniqueId(), deviceSession); - sessionsByEndpoint.put(endpoint, endpointSessions); + sessionsByEndpoint.put(remoteAddress, endpointSessions); sessionsByDeviceId.put(device.getId(), deviceSession); if (oldSession == null) { @@ -182,8 +181,7 @@ public class ConnectionManager implements BroadcastInterface { } public void deviceDisconnected(Channel channel, boolean supportsOffline) { - Endpoint endpoint = new Endpoint(channel, channel.remoteAddress()); - Map endpointSessions = sessionsByEndpoint.remove(endpoint); + Map endpointSessions = sessionsByEndpoint.remove(channel.remoteAddress()); if (endpointSessions != null) { for (DeviceSession deviceSession : endpointSessions.values()) { if (supportsOffline) { @@ -204,8 +202,7 @@ public class ConnectionManager implements BroadcastInterface { DeviceSession deviceSession = sessionsByDeviceId.remove(deviceId); if (deviceSession != null) { cacheManager.removeDevice(deviceId); - Endpoint endpoint = new Endpoint(deviceSession.getChannel(), deviceSession.getRemoteAddress()); - sessionsByEndpoint.computeIfPresent(endpoint, (e, sessions) -> { + sessionsByEndpoint.computeIfPresent(deviceSession.getRemoteAddress(), (e, sessions) -> { sessions.remove(deviceSession.getUniqueId()); return sessions.isEmpty() ? null : sessions; }); @@ -337,11 +334,24 @@ public class ConnectionManager implements BroadcastInterface { } } + public synchronized void updateLog(LogRecord record) { + var sessions = sessionsByEndpoint.getOrDefault(record.getAddress(), Map.of()); + for (var session : sessions.entrySet()) { + record.setUniqueId(session.getKey()); + for (long userId : deviceUsers.getOrDefault(session.getValue().getDeviceId(), Set.of())) { + for (UpdateListener listener : listeners.getOrDefault(userId, Set.of())) { + listener.onUpdateLog(record); + } + } + } + } + public interface UpdateListener { void onKeepalive(); void onUpdateDevice(Device device); void onUpdatePosition(Position position); void onUpdateEvent(Event event); + void onUpdateLog(LogRecord record); } public synchronized void addListener(long userId, UpdateListener listener) throws StorageException { diff --git a/src/main/java/org/traccar/session/Endpoint.java b/src/main/java/org/traccar/session/Endpoint.java deleted file mode 100644 index 76aac3444..000000000 --- a/src/main/java/org/traccar/session/Endpoint.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2022 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.session; - -import io.netty.channel.Channel; - -import java.net.SocketAddress; -import java.util.Objects; - -public class Endpoint { - - private final Channel channel; - private final SocketAddress remoteAddress; - - public Endpoint(Channel channel, SocketAddress remoteAddress) { - this.channel = channel; - this.remoteAddress = remoteAddress; - } - - public Channel getChannel() { - return channel; - } - - public SocketAddress getRemoteAddress() { - return remoteAddress; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Endpoint endpoint = (Endpoint) o; - return channel.equals(endpoint.channel) && remoteAddress.equals(endpoint.remoteAddress); - } - - @Override - public int hashCode() { - return Objects.hash(channel, remoteAddress); - } - -} -- cgit v1.2.3 From 293a3dbf93b0d1924ecb96f8a3b11b65fbaa4248 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 28 Dec 2023 08:44:32 -0800 Subject: Show protocol instead of port --- .../java/org/traccar/handler/StandardLoggingHandler.java | 1 + src/main/java/org/traccar/model/LogRecord.java | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java index b495747d3..5978d632e 100644 --- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java +++ b/src/main/java/org/traccar/handler/StandardLoggingHandler.java @@ -68,6 +68,7 @@ public class StandardLoggingHandler extends ChannelDuplexHandler { if (networkMessage.getMessage() instanceof ByteBuf) { LogRecord record = new LogRecord(); record.setAddress((InetSocketAddress) networkMessage.getRemoteAddress()); + record.setProtocol(protocol); record.setData(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage())); return record; } diff --git a/src/main/java/org/traccar/model/LogRecord.java b/src/main/java/org/traccar/model/LogRecord.java index 3feaadec2..beabdf2f4 100644 --- a/src/main/java/org/traccar/model/LogRecord.java +++ b/src/main/java/org/traccar/model/LogRecord.java @@ -32,14 +32,20 @@ public class LogRecord { return address; } - public int getPort() { - return address.getPort(); - } - public String getHost() { return address.getHostString(); } + private String protocol; + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + private String uniqueId; public String getUniqueId() { -- cgit v1.2.3 From a9e0e6531abf5370713cb1846f869e9d77fafdff Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 29 Dec 2023 07:35:39 -0800 Subject: Improve basic GL200 pattern --- .../org/traccar/protocol/Gl200TextProtocolDecoder.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index a73981614..ffeeab7de 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1405,15 +1405,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .number("(d{15}|x{14}),") // imei .any() .text(",") - .number("(d{1,2})?,") // hdop - .number("(d{1,3}.d)?,") // speed - .number("(d{1,3})?,") // course - .number("(-?d{1,5}.d)?,") // altitude - .number("(-?d{1,3}.d{6})?,") // longitude - .number("(-?d{1,2}.d{6})?,") // latitude + .number("(d{1,2}),") // hdop + .groupBegin() + .number("(d{1,3}.d),") // speed + .number("(d{1,3}),") // course + .number("(-?d{1,5}.d),") // altitude + .number("(-?d{1,3}.d{6}),") // longitude + .number("(-?d{1,2}.d{6}),") // latitude .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .number("(dd)(dd)(dd)") // time (hhmmss) .text(",") + .or() + .text(",,,,,,") + .groupEnd() .number("(d+),") // mcc .number("(d+),") // mnc .number("(x+),") // lac -- cgit v1.2.3 From 0b3842c7df86f603853149746f65b41a085830c9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 29 Dec 2023 07:36:45 -0800 Subject: Add GT300 test case --- src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java index d835f2f27..3701fa772 100644 --- a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl100ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl100ProtocolDecoder(null)); + verifyPosition(decoder, text( + "+RESP:GTRTL,359464032011616,1,0,0,0,0.1,0,1662.5,,36.822301,-1.309476,20230706032920,0639,0002,08DF,1F5E,00,095,0101050105,4470")); + verifyPosition(decoder, text( "+RESP:GTLGL,359464030492644,1,2,1,0,0.4,0,299.7,1,5.455551,51.449776,20160311083229,0204,0016,03EC,BD94,00,0036,0102090501")); -- cgit v1.2.3 From 3b9333bec68898b08894b999b6f95c39e7e21f08 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 29 Dec 2023 07:44:12 -0800 Subject: Add Meitrack engine hours --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 1235ca9fe..c37d1fe47 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -534,6 +534,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0xA2: position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedIntLE() * 0.01); break; + case 0xFEF4: + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 60000); + break; default: buf.readUnsignedIntLE(); break; -- cgit v1.2.3 From 30b74bc637b4f1165e040c23324f3504897d2b97 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 29 Dec 2023 07:57:17 -0800 Subject: Decode RST 4G driver id --- src/main/java/org/traccar/protocol/RstProtocolDecoder.java | 10 +++++++++- src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java index d53675b7f..2493f0d9f 100644 --- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -42,7 +42,7 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { .expression("(.{5});") // firmware .number("(d{9});") // serial number .number("(d+);") // index - .number("d+;") // type + .number("(d+);") // type .groupBegin() .number("(dd)-(dd)-(dddd) ") // event date .number("(dd):(dd):(dd);") // event time @@ -69,8 +69,10 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { .number("x{4};") // sensors .number("(xx);") // status 1 .number("(xx);") // status 2 + .expression("(.*)") // additional data .groupEnd("?") .any() + .text("FIM;") .compile(); @Override @@ -87,6 +89,7 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { String firmware = parser.next(); String serial = parser.next(); int index = parser.nextInt(); + int type = parser.nextInt(); if (channel != null) { String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";6;FIM;"; @@ -133,6 +136,11 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, (int) parser.nextHexInt().byteValue()); position.set(Position.KEY_STATUS, (parser.nextHexInt() << 8) + parser.nextHexInt()); + String[] values = parser.next().split(";"); + if (type == 55) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, values[0]); + } + return position; } else { diff --git a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java index 0e8aefe51..fc932fe9e 100644 --- a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class RstProtocolDecoderTest extends ProtocolTest { var decoder = inject(new RstProtocolDecoder(null)); + verifyAttribute(decoder, text( + "RST;A;RST-MINIv5;V9.08;009767055;248;55;14-12-2023 19:34:20;14-12-2023 19:34:21;-12.923640;-38.388313;0;14;17;1;4;15;00;B0;00;1A;02;12.18;4.02;65;21;FE;0000;01;C0;001606017031;0002;FIM;"), + Position.KEY_DRIVER_UNIQUE_ID, "001606017031"); + verifyNull(decoder, text( "RST;A;RST-MINIv2;V7.04;008051261;124;29;04-04-2021 17:27:26;04-04-2021 17:27:26;-1.280811;-47.931755;7353;79;1;14;7315;26;10;0;1855;0;0;0;0;5;5;-1.280821;-47.931747;04-04-2021 17:52:23;6;-1.280863;-47.931770;04-04-2021 18:12:19;5;-1.280844;-47.931763;04-04-2021 17:28:02;5;-1.280900;-47.931770;04-04-2021 19:04:27;4;-1.280843;-47.931747;04-04-2021 18:21:45;04-04-2021 19:29:59;04-04-2021 19:29:59;-1.280770;-47.931595;1;15;0;0;0;0;FIM;")); -- cgit v1.2.3 From e7fa59e3e5c81f45f248ac7c4a1de6ba919b0065 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 29 Dec 2023 15:10:10 -0800 Subject: Support MettaX new alarms --- .../java/org/traccar/protocol/HuabaoProtocolDecoder.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 881209120..a102e9e44 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -131,7 +131,10 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 8)) { return Position.ALARM_POWER_OFF; } - if (BitUtil.check(value, 17)) { + if (BitUtil.check(value, 15)) { + return Position.ALARM_VIBRATION; + } + if (BitUtil.check(value, 16) || BitUtil.check(value, 17)) { return Position.ALARM_TAMPERING; } if (BitUtil.check(value, 20)) { @@ -140,7 +143,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 28)) { return Position.ALARM_MOVEMENT; } - if (BitUtil.check(value, 29)) { + if (BitUtil.check(value, 29) || BitUtil.check(value, 30)) { return Position.ALARM_ACCIDENT; } return null; @@ -488,6 +491,14 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 10); buf.readUnsignedByte(); // reserved break; + case 0x57: + int alarm = buf.readUnsignedShort(); + position.set(Position.KEY_ALARM, BitUtil.check(alarm, 8) ? Position.ALARM_ACCELERATION : null); + position.set(Position.KEY_ALARM, BitUtil.check(alarm, 9) ? Position.ALARM_BRAKING : null); + position.set(Position.KEY_ALARM, BitUtil.check(alarm, 10) ? Position.ALARM_CORNERING : null); + buf.readUnsignedShort(); // external switch state + buf.skipBytes(4); // reserved + break; case 0x60: int event = buf.readUnsignedShort(); position.set(Position.KEY_EVENT, event); -- cgit v1.2.3 From 4959d904581d2408171917b8ee2cac38acb997e7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Dec 2023 15:20:16 -0800 Subject: Logs from unknown device --- src/main/java/org/traccar/model/LogRecord.java | 10 ++++++++ .../org/traccar/session/ConnectionManager.java | 28 +++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/model/LogRecord.java b/src/main/java/org/traccar/model/LogRecord.java index beabdf2f4..c19163af3 100644 --- a/src/main/java/org/traccar/model/LogRecord.java +++ b/src/main/java/org/traccar/model/LogRecord.java @@ -56,6 +56,16 @@ public class LogRecord { this.uniqueId = uniqueId; } + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + private String data; public String getData() { diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 7541cedfb..a598260aa 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -66,6 +66,7 @@ public class ConnectionManager implements BroadcastInterface { private final Map sessionsByDeviceId = new ConcurrentHashMap<>(); private final Map> sessionsByEndpoint = new ConcurrentHashMap<>(); + private final Map unknownByEndpoint = new ConcurrentHashMap<>(); private final Config config; private final CacheManager cacheManager; @@ -122,13 +123,15 @@ public class ConnectionManager implements BroadcastInterface { Device device = deviceLookupService.lookup(uniqueIds); + String firstUniqueId = uniqueIds[0]; if (device == null && config.getBoolean(Keys.DATABASE_REGISTER_UNKNOWN)) { - if (uniqueIds[0].matches(config.getString(Keys.DATABASE_REGISTER_UNKNOWN_REGEX))) { - device = addUnknownDevice(uniqueIds[0]); + if (firstUniqueId.matches(config.getString(Keys.DATABASE_REGISTER_UNKNOWN_REGEX))) { + device = addUnknownDevice(firstUniqueId); } } if (device != null) { + unknownByEndpoint.remove(remoteAddress); device.checkDisabled(); DeviceSession oldSession = sessionsByDeviceId.remove(device.getId()); @@ -153,6 +156,7 @@ public class ConnectionManager implements BroadcastInterface { return deviceSession; } else { + unknownByEndpoint.put(remoteAddress, firstUniqueId); LOGGER.warn("Unknown device - " + String.join(" ", uniqueIds) + " (" + ((InetSocketAddress) remoteAddress).getHostString() + ")"); return null; @@ -181,7 +185,8 @@ public class ConnectionManager implements BroadcastInterface { } public void deviceDisconnected(Channel channel, boolean supportsOffline) { - Map endpointSessions = sessionsByEndpoint.remove(channel.remoteAddress()); + SocketAddress remoteAddress = channel.remoteAddress(); + Map endpointSessions = sessionsByEndpoint.remove(remoteAddress); if (endpointSessions != null) { for (DeviceSession deviceSession : endpointSessions.values()) { if (supportsOffline) { @@ -191,6 +196,7 @@ public class ConnectionManager implements BroadcastInterface { cacheManager.removeDevice(deviceSession.getDeviceId()); } } + unknownByEndpoint.remove(remoteAddress); } public void deviceUnknown(long deviceId) { @@ -336,9 +342,19 @@ public class ConnectionManager implements BroadcastInterface { public synchronized void updateLog(LogRecord record) { var sessions = sessionsByEndpoint.getOrDefault(record.getAddress(), Map.of()); - for (var session : sessions.entrySet()) { - record.setUniqueId(session.getKey()); - for (long userId : deviceUsers.getOrDefault(session.getValue().getDeviceId(), Set.of())) { + if (sessions.isEmpty()) { + String unknownUniqueId = unknownByEndpoint.get(record.getAddress()); + if (unknownUniqueId != null) { + record.setUniqueId(unknownUniqueId); + listeners.values().stream() + .flatMap(Set::stream) + .forEach((listener) -> listener.onUpdateLog(record)); + } + } else { + var firstEntry = sessions.entrySet().iterator().next(); + record.setUniqueId(firstEntry.getKey()); + record.setDeviceId(firstEntry.getValue().getDeviceId()); + for (long userId : deviceUsers.getOrDefault(record.getDeviceId(), Set.of())) { for (UpdateListener listener : listeners.getOrDefault(userId, Set.of())) { listener.onUpdateLog(record); } -- cgit v1.2.3 From c15525531bbdc953b0c11e5365540f68b0da1e4e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Jan 2024 11:31:02 -0800 Subject: Queclink GV58LAU improvements --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 36 +++++++++++----------- .../protocol/Gl200TextProtocolDecoderTest.java | 9 +++--- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index ffeeab7de..0628a06d4 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -61,7 +61,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_ACK = new PatternBuilder() .text("+ACK:GT") .expression("...,") // type - .number("([0-9A-Z]{2}xxxx),") // protocol version + .expression("(.{6}|.{10}),") // protocol version .number("(d{15}|x{14}),") // imei .any().text(",") .number("(dddd)(dd)(dd)") // date (yyyymmdd) @@ -130,7 +130,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_INF = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTINF,") - .number("[0-9A-Z]{2}xxxx,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("(?:[0-9A-Z]{17},)?") // vin .expression("(?:[^,]+)?,") // device name @@ -231,7 +231,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_VER = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTVER,") - .number("[0-9A-Z]{2}xxxx,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .expression("([^,]*),") // device type @@ -340,7 +340,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_OBD = new PatternBuilder() .text("+RESP:GTOBD,") - .number("[0-9A-Z]{2}xxxx,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("(?:[0-9A-Z]{17})?,") // vin .expression("[^,]{0,20},") // device name @@ -636,7 +636,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_FRI = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("(?:([0-9A-Z]{17}),)?") // vin .expression("[^,]*,") // device name @@ -764,7 +764,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_ERI = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTERI,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("(x{8}),") // mask @@ -905,7 +905,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_IGN = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTIG[NF],") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("d+,") // ignition off duration @@ -939,7 +939,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_LSW = new PatternBuilder() .text("+RESP:").expression("GT[LT]SW,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("[01],") // type @@ -970,7 +970,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_IDA = new PatternBuilder() .text("+RESP:GTIDA,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,,") // device name .number("([^,]+),") // rfid @@ -1006,7 +1006,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_WIF = new PatternBuilder() .text("+RESP:GTWIF,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("(d+),") // count @@ -1047,7 +1047,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_GSM = new PatternBuilder() .text("+RESP:GTGSM,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("(?:STR|CTN|NMR|RTL),") // fix type .expression("(.*)") // cells @@ -1086,7 +1086,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_PNA = new PatternBuilder() .text("+RESP:GT").expression("P[NF]A,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("(dddd)(dd)(dd)") // date (yyyymmdd) @@ -1112,7 +1112,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_DAR = new PatternBuilder() .text("+RESP:GTDAR,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("(d),") // warning type @@ -1151,7 +1151,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_DTT = new PatternBuilder() .text("+RESP:GTDTT,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,,,") // device name .number("d,") // data type @@ -1189,7 +1189,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_BAA = new PatternBuilder() .text("+RESP:GTBAA,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("x+,") // index @@ -1245,7 +1245,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_BID = new PatternBuilder() .text("+RESP:GTBID,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("d,") // count @@ -1287,7 +1287,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_LSA = new PatternBuilder() .text("+RESP:GTLSA,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("d,") // event state 1 @@ -1327,7 +1327,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name .number("d*,") diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 199012ca0..2c012eb6f 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,18 +11,17 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); - verifyAttribute(decoder, buffer( - "+RESP:GTFRI,710303,868487004352084,GL530MG,0,0,1,1,16.6,0,9.4,121.307910,31.127837,20230815050629,0460,0000,1815,B93B,26,0,8964,90,1,0,26.6,20230815130830,0174$"), - Position.PREFIX_TEMP + 1, 26.6); + verifyPositions(decoder, buffer( + "+RESP:GTFRI,8020040305,866314060272661,,,50,1,1,0.0,0,2957.9,-78.691727,-0.951205,20231227162916,,,,,00,0.0,,,,,100,210100,,,,20231227162916,0117$")); - verifyPosition(decoder, buffer( + verifyPositions(decoder, buffer( "+BUFF:GTFRI,8020040200,866314060249032,,12194,10,1,3,0.0,0,20.1,-71.596533,-33.524718,20230926200338,0730,0001,772A,052B253E,02,0,0.0,,,,,0,420000,,,,20230926200340,1549$")); verifyAttribute(decoder, buffer( "+RESP:GTFRI,423037,866884047716519,GT501,0,1,1,5,12,0.1,0,46.8,-95.559173,30.109955,20231110185836,6,0e36c9916485,-50,,,,e831cd5eb79d,-73,,,,ccf4110c4bd5,-79,,,,acdb48973168,-79,,,,80ab4dc323c4,-82,,,,ec8eb5cfa1c6,-89,,,,310,10,711D,81ECF0F,00,,93,20231110185839,0005$"), Position.KEY_BATTERY_LEVEL, 93); - verifyPosition(decoder, buffer( + verifyPositions(decoder, buffer( "+RESP:GTFRI,8020040200,866314060109269,,,10,1,1,0.0,0,9.0,-71.596601,-33.524595,20230722145338,0730,0001,772A,052B253E,00,0.0,,,,,100,210100,,,,20230722145341,0F4C$")); verifyAttributes(decoder, buffer( -- cgit v1.2.3 From 346a860b0aae7097445aa5aa22f37a88d9d7955e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 7 Jan 2024 12:13:47 -0800 Subject: User and device expiration emails --- src/main/java/org/traccar/config/Keys.java | 38 ++++-- .../java/org/traccar/schedule/ScheduleManager.java | 3 +- .../java/org/traccar/schedule/TaskExpirations.java | 130 +++++++++++++++++++++ templates/full/deviceExpiration.vm | 7 ++ templates/full/deviceExpirationReminder.vm | 7 ++ templates/full/userExpiration.vm | 7 ++ templates/full/userExpirationReminder.vm | 7 ++ 7 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 src/main/java/org/traccar/schedule/TaskExpirations.java create mode 100644 templates/full/deviceExpiration.vm create mode 100644 templates/full/deviceExpirationReminder.vm create mode 100644 templates/full/userExpiration.vm create mode 100644 templates/full/userExpirationReminder.vm diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 3059c4f4b..3528dafa0 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -489,14 +489,6 @@ public final class Keys { "database.throttleUnknown", List.of(KeyType.CONFIG)); - /** - * By default, server syncs with the database if it encounters and unknown device. This flag allows to disable that - * behavior to improve performance in some cases. - */ - public static final ConfigKey DATABASE_IGNORE_UNKNOWN = new BooleanConfigKey( - "database.ignoreUnknown", - List.of(KeyType.CONFIG)); - /** * Automatically register unknown devices in the database. */ @@ -664,7 +656,7 @@ public final class Keys { /** * OpenID Connect Authorization URL. * This can usually be found in the documentation of your identity provider or by using the well-known - * configuration endpoint, eg. https://auth.example.com//.well-known/openid-configuration + * configuration endpoint, e.g. https://auth.example.com//.well-known/openid-configuration * Required to enable SSO if openid.issuerUrl is not set. */ public static final ConfigKey OPENID_AUTH_URL = new StringConfigKey( @@ -1225,6 +1217,34 @@ public final class Keys { "notificator.telegram.sendLocation", List.of(KeyType.CONFIG)); + /** + * Enable user expiration email notification. + */ + public static final ConfigKey NOTIFICATION_EXPIRATION_USER = new BooleanConfigKey( + "notification.expiration.user", + List.of(KeyType.CONFIG)); + + /** + * User expiration reminder. Value in milliseconds. + */ + public static final ConfigKey NOTIFICATION_EXPIRATION_USER_REMINDER = new LongConfigKey( + "notification.expiration.user.reminder", + List.of(KeyType.CONFIG)); + + /** + * Enable device expiration email notification. + */ + public static final ConfigKey NOTIFICATION_EXPIRATION_DEVICE = new BooleanConfigKey( + "notification.expiration.device", + List.of(KeyType.CONFIG)); + + /** + * Device expiration reminder. Value in milliseconds. + */ + public static final ConfigKey NOTIFICATION_EXPIRATION_DEVICE_REMINDER = new LongConfigKey( + "notification.expiration.device.reminder", + List.of(KeyType.CONFIG)); + /** * Maximum time period for reports in seconds. Can be useful to prevent users to request unreasonably long reports. * By default there is no limit. diff --git a/src/main/java/org/traccar/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java index 38e8f281c..3756d955b 100644 --- a/src/main/java/org/traccar/schedule/ScheduleManager.java +++ b/src/main/java/org/traccar/schedule/ScheduleManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2024 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. @@ -39,6 +39,7 @@ public class ScheduleManager implements LifecycleObject { public void start() { executor = Executors.newSingleThreadScheduledExecutor(); var tasks = List.of( + TaskExpirations.class, TaskDeleteTemporary.class, TaskReports.class, TaskDeviceInactivityCheck.class, diff --git a/src/main/java/org/traccar/schedule/TaskExpirations.java b/src/main/java/org/traccar/schedule/TaskExpirations.java new file mode 100644 index 000000000..94f855c5f --- /dev/null +++ b/src/main/java/org/traccar/schedule/TaskExpirations.java @@ -0,0 +1,130 @@ +/* + * Copyright 2024 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.schedule; + +import jakarta.inject.Inject; +import jakarta.mail.MessagingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.mail.MailManager; +import org.traccar.model.Device; +import org.traccar.model.Disableable; +import org.traccar.model.Server; +import org.traccar.model.User; +import org.traccar.notification.TextTemplateFormatter; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class TaskExpirations implements ScheduleTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(TaskExpirations.class); + + private static final long CHECK_PERIOD_HOURS = 1; + + private final Config config; + private final Storage storage; + private final TextTemplateFormatter textTemplateFormatter; + private final MailManager mailManager; + + @Inject + public TaskExpirations( + Config config, Storage storage, TextTemplateFormatter textTemplateFormatter, MailManager mailManager) { + this.config = config; + this.storage = storage; + this.textTemplateFormatter = textTemplateFormatter; + this.mailManager = mailManager; + } + + @Override + public void schedule(ScheduledExecutorService executor) { + executor.scheduleAtFixedRate(this, CHECK_PERIOD_HOURS, CHECK_PERIOD_HOURS, TimeUnit.HOURS); + } + + private boolean checkTimeTrigger(Disableable disableable, long currentTime, long offsetTime) { + if (disableable.getExpirationTime() != null) { + long previousTime = currentTime - TimeUnit.HOURS.toMillis(CHECK_PERIOD_HOURS); + long expirationTime = disableable.getExpirationTime().getTime() + offsetTime; + return previousTime < expirationTime && currentTime >= expirationTime; + } + return false; + } + + private void sendUserExpiration( + Server server, User user, String template) throws MessagingException { + var velocityContext = textTemplateFormatter.prepareContext(server, user); + velocityContext.put("expiration", user.getExpirationTime()); + var fullMessage = textTemplateFormatter.formatMessage(velocityContext, template, "full"); + mailManager.sendMessage(user, true, fullMessage.getSubject(), fullMessage.getBody()); + } + + private void sendDeviceExpiration( + Server server, Device device, String template) throws MessagingException, StorageException { + var users = storage.getObjects(User.class, new Request( + new Columns.All(), new Condition.Permission(User.class, Device.class, device.getId()))); + for (User user : users) { + var velocityContext = textTemplateFormatter.prepareContext(server, user); + velocityContext.put("expiration", device.getExpirationTime()); + velocityContext.put("device", device); + var fullMessage = textTemplateFormatter.formatMessage(velocityContext, template, "full"); + mailManager.sendMessage(user, true, fullMessage.getSubject(), fullMessage.getBody()); + } + } + + @Override + public void run() { + try { + + long currentTime = System.currentTimeMillis(); + Server server = storage.getObject(Server.class, new Request(new Columns.All())); + + if (config.getBoolean(Keys.NOTIFICATION_EXPIRATION_USER)) { + long reminder = config.getLong(Keys.NOTIFICATION_EXPIRATION_USER_REMINDER); + var users = storage.getObjects(User.class, new Request(new Columns.All())); + for (User user : users) { + if (checkTimeTrigger(user, currentTime, 0)) { + sendUserExpiration(server, user, "userExpiration"); + } else if (reminder > 0 && checkTimeTrigger(user, currentTime, -reminder)) { + sendUserExpiration(server, user, "userExpirationReminder"); + } + } + } + + if (config.getBoolean(Keys.NOTIFICATION_EXPIRATION_DEVICE)) { + long reminder = config.getLong(Keys.NOTIFICATION_EXPIRATION_USER_REMINDER); + var devices = storage.getObjects(Device.class, new Request(new Columns.All())); + for (Device device : devices) { + if (checkTimeTrigger(device, currentTime, 0)) { + sendDeviceExpiration(server, device, "deviceExpiration"); + } else if (reminder > 0 && checkTimeTrigger(device, currentTime, -reminder)) { + sendDeviceExpiration(server, device, "deviceExpirationReminder"); + } + } + } + + } catch (StorageException | MessagingException e) { + LOGGER.warn("Failed to check expirations", e); + } + } + +} diff --git a/templates/full/deviceExpiration.vm b/templates/full/deviceExpiration.vm new file mode 100644 index 000000000..879b31778 --- /dev/null +++ b/templates/full/deviceExpiration.vm @@ -0,0 +1,7 @@ +#set($subject = "Device expiration") + + + +Your device $device.name has expired. + + diff --git a/templates/full/deviceExpirationReminder.vm b/templates/full/deviceExpirationReminder.vm new file mode 100644 index 000000000..aa47ac0ed --- /dev/null +++ b/templates/full/deviceExpirationReminder.vm @@ -0,0 +1,7 @@ +#set($subject = "Device expiration reminder") + + + +Your device $device.name will expire on $dateTool.format("YYYY-MM-dd", $expiration, $locale, $timezone). + + diff --git a/templates/full/userExpiration.vm b/templates/full/userExpiration.vm new file mode 100644 index 000000000..43fe2563e --- /dev/null +++ b/templates/full/userExpiration.vm @@ -0,0 +1,7 @@ +#set($subject = "Account expiration") + + + +Your user account has expired. + + diff --git a/templates/full/userExpirationReminder.vm b/templates/full/userExpirationReminder.vm new file mode 100644 index 000000000..ecdee0588 --- /dev/null +++ b/templates/full/userExpirationReminder.vm @@ -0,0 +1,7 @@ +#set($subject = "Account expiration reminder") + + + +Your user account will expire on $dateTool.format("YYYY-MM-dd", $expiration, $locale, $timezone). + + -- cgit v1.2.3 From 64b2d09ecc58ba68eea39fdb538f22accf386e72 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 13 Jan 2024 08:14:29 -0800 Subject: Add Minifinder config command --- src/main/java/org/traccar/protocol/Minifinder2Protocol.java | 3 ++- src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java index c12933b81..082b9146d 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java +++ b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java @@ -31,7 +31,8 @@ public class Minifinder2Protocol extends BaseProtocol { @Inject public Minifinder2Protocol(Config config) { setSupportedDataCommands( - Command.TYPE_FIRMWARE_UPDATE); + Command.TYPE_FIRMWARE_UPDATE, + Command.TYPE_CONFIGURATION); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java index fab3c3a6d..72ac9db4e 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java @@ -48,6 +48,13 @@ public class Minifinder2ProtocolEncoder extends BaseProtocolEncoder { @Override protected Object encodeCommand(Command command) { + if (command.getType().equals(Command.TYPE_CONFIGURATION)) { + ByteBuf content = Unpooled.buffer(); + content.writeByte(Minifinder2ProtocolDecoder.MSG_CONFIGURATION); + content.writeByte(1); // length + content.writeByte(0xF0); // type + } + Device device = getCacheManager().getObject(Device.class, command.getDeviceId()); if ("Nano".equalsIgnoreCase(device.getModel())) { ByteBuf content = Unpooled.buffer(); -- cgit v1.2.3 From 093cc360cd1ac64b50b59780b621a58a043e1623 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 Jan 2024 08:20:49 -0800 Subject: Update project dependencies --- build.gradle | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index a51ebaff0..9239360bc 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ compileJava.options.encoding = "UTF-8" jar.destinationDirectory = file("$projectDir/target") checkstyle { - toolVersion = "10.12.0" + toolVersion = "10.12.5" configFile = "gradle/checkstyle.xml" as File checkstyleTest.enabled = false } @@ -27,11 +27,11 @@ enforce { ext { guiceVersion = "7.0.0" - jettyVersion = "11.0.18" - jerseyVersion = "3.1.3" - jacksonVersion = "2.15.2" // same version as jersey-media-json-jackson dependency - protobufVersion = "3.24.0" - jxlsVersion = "2.13.0" + jettyVersion = "11.0.19" + jerseyVersion = "3.1.5" + jacksonVersion = "2.15.3" // same version as jersey-media-json-jackson dependency + protobufVersion = "3.25.2" + jxlsVersion = "2.14.0" junitVersion = "5.10.1" } @@ -45,12 +45,12 @@ dependencies { implementation "commons-codec:commons-codec:1.16.0" implementation "com.h2database:h2:2.2.224" implementation "com.mysql:mysql-connector-j:8.2.0" - implementation "org.mariadb.jdbc:mariadb-java-client:3.3.0" - implementation "org.postgresql:postgresql:42.6.0" + implementation "org.mariadb.jdbc:mariadb-java-client:3.3.2" + implementation "org.postgresql:postgresql:42.7.1" implementation "com.microsoft.sqlserver:mssql-jdbc:12.4.2.jre11" implementation "com.zaxxer:HikariCP:5.1.0" - implementation "io.netty:netty-all:4.1.101.Final" - implementation "org.slf4j:slf4j-jdk14:2.0.9" + implementation "io.netty:netty-all:4.1.104.Final" + implementation "org.slf4j:slf4j-jdk14:2.0.11" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" @@ -66,7 +66,7 @@ dependencies { implementation "org.glassfish.jersey.containers:jersey-container-servlet:$jerseyVersion" implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion" implementation "org.glassfish.jersey.inject:jersey-hk2:$jerseyVersion" - implementation "org.glassfish.hk2:guice-bridge:3.0.4" // same version as jersey-hk2 + implementation "org.glassfish.hk2:guice-bridge:3.0.5" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp:$jacksonVersion" implementation "org.liquibase:liquibase-core:4.23.2" // upgrade has issues @@ -79,20 +79,20 @@ dependencies { implementation "org.mnode.ical4j:ical4j:3.2.14" implementation "org.locationtech.spatial4j:spatial4j:0.8" implementation "org.locationtech.jts:jts-core:1.19.0" - implementation "net.java.dev.jna:jna-platform:5.13.0" + implementation "net.java.dev.jna:jna-platform:5.14.0" implementation "com.github.jnr:jnr-posix:3.1.18" implementation "com.google.protobuf:protobuf-java:$protobufVersion" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.592" - implementation "org.apache.kafka:kafka-clients:3.6.0" + implementation "com.amazonaws:aws-java-sdk-sns:1.12.636" + implementation "org.apache.kafka:kafka-clients:3.6.1" implementation "com.hivemq:hivemq-mqtt-client:1.3.3" - implementation "redis.clients:jedis:5.0.2" + implementation "redis.clients:jedis:5.1.0" implementation "com.google.firebase:firebase-admin:9.2.0" - implementation "com.nimbusds:oauth2-oidc-sdk:11.6" + implementation "com.nimbusds:oauth2-oidc-sdk:11.9.1" implementation "com.rabbitmq:amqp-client:5.20.0" implementation "com.warrenstrange:googleauth:1.5.0" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:5.7.0" + testImplementation "org.mockito:mockito-core:5.8.0" } test { -- cgit v1.2.3 From 172422eb5262a8e0ff560b689504c0365c8e0503 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 Jan 2024 08:23:28 -0800 Subject: Fix style issues --- src/main/java/org/traccar/WindowsService.java | 4 ++-- src/main/java/org/traccar/database/DeviceLookupService.java | 2 +- src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/WindowsService.java b/src/main/java/org/traccar/WindowsService.java index f233337a7..08eba25a6 100644 --- a/src/main/java/org/traccar/WindowsService.java +++ b/src/main/java/org/traccar/WindowsService.java @@ -170,7 +170,7 @@ public abstract class WindowsService { public abstract void run(); - private class ServiceMain implements SERVICE_MAIN_FUNCTION { + private final class ServiceMain implements SERVICE_MAIN_FUNCTION { public void callback(int dwArgc, Pointer lpszArgv) { ServiceControl serviceControl = new ServiceControl(); @@ -203,7 +203,7 @@ public abstract class WindowsService { } - private class ServiceControl implements HandlerEx { + private final class ServiceControl implements HandlerEx { public int callback(int dwControl, int dwEventType, Pointer lpEventData, Pointer lpContext) { switch (dwControl) { diff --git a/src/main/java/org/traccar/database/DeviceLookupService.java b/src/main/java/org/traccar/database/DeviceLookupService.java index 6ec6841a1..90d23531e 100644 --- a/src/main/java/org/traccar/database/DeviceLookupService.java +++ b/src/main/java/org/traccar/database/DeviceLookupService.java @@ -49,7 +49,7 @@ public class DeviceLookupService { private final boolean throttlingEnabled; - private static class IdentifierInfo { + private static final class IdentifierInfo { private long lastQuery; private long delay; private Timeout timeout; diff --git a/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java index 896c7a2d2..9704cf099 100644 --- a/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java @@ -96,7 +96,7 @@ public class Mta6ProtocolDecoder extends BaseProtocolDecoder { } - private static class TimeReader extends FloatReader { + private static final class TimeReader extends FloatReader { private long weekNumber; -- cgit v1.2.3 From c68318800bac25249ae9b958b8672f2e50dd2db9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 Jan 2024 08:35:53 -0800 Subject: Update version number --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 9239360bc..41baa7f89 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.10", + "Implementation-Version": "5.11", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 23daf6e13..68258dcb5 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.10 +AppVersion=5.11 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index 982e1bff1..9268e1a0d 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.10", + "version": "5.11", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From ba1e70e50f6310ec9f331a7e585f004ca4e17298 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 14 Jan 2024 14:35:12 -0800 Subject: Update web submodule --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index dc46059f6..d1a9c0857 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit dc46059f6bfeedca04333c2839872055db066dc6 +Subproject commit d1a9c08571683184ce10b7db5890e2a75bf6179c -- cgit v1.2.3 From 079eaa6ed49813f4050076ac45849f6e4334e45b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 Jan 2024 08:20:34 -0800 Subject: Fix duplicate notifications (fix #5245) --- src/main/java/org/traccar/database/NotificationManager.java | 2 +- src/main/java/org/traccar/session/cache/CacheManager.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 45263ff3c..65437f0a1 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -87,7 +87,7 @@ public class NotificationManager { return; } - var notifications = cacheManager.getDeviceNotifications(event.getDeviceId()) + var notifications = cacheManager.getDeviceNotifications(event.getDeviceId()).stream() .filter(notification -> notification.getType().equals(event.getType())) .filter(notification -> { if (event.getType().equals(Event.TYPE_ALARM)) { diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index bb9b4c995..89b25af2f 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -136,14 +136,15 @@ public class CacheManager implements BroadcastInterface { } } - public Stream getDeviceNotifications(long deviceId) { + public Set getDeviceNotifications(long deviceId) { try { lock.readLock().lock(); var direct = graph.getObjects(Device.class, deviceId, Notification.class, Set.of(Group.class), true) .map(BaseModel::getId) .collect(Collectors.toUnmodifiableSet()); return graph.getObjects(Device.class, deviceId, Notification.class, Set.of(Group.class, User.class), true) - .filter(notification -> notification.getAlways() || direct.contains(notification.getId())); + .filter(notification -> notification.getAlways() || direct.contains(notification.getId())) + .collect(Collectors.toUnmodifiableSet()); } finally { lock.readLock().unlock(); } -- cgit v1.2.3 From 2b893df60f62ee8b363cd6dd528c155bb5124c5c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 Jan 2024 08:23:19 -0800 Subject: Fix lint issue --- src/main/java/org/traccar/session/cache/CacheManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 89b25af2f..064e5672f 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -49,7 +49,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; -import java.util.stream.Stream; @Singleton public class CacheManager implements BroadcastInterface { -- cgit v1.2.3 From a531585474ca9ee7437d2a5b1698d1cf5f507a09 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 Jan 2024 15:49:36 -0800 Subject: Add notification to templates --- src/main/java/org/traccar/notification/NotificationFormatter.java | 5 ++++- src/main/java/org/traccar/notificators/NotificatorFirebase.java | 2 +- src/main/java/org/traccar/notificators/NotificatorMail.java | 2 +- src/main/java/org/traccar/notificators/NotificatorPushover.java | 2 +- src/main/java/org/traccar/notificators/NotificatorSms.java | 2 +- src/main/java/org/traccar/notificators/NotificatorTelegram.java | 2 +- src/main/java/org/traccar/notificators/NotificatorTraccar.java | 2 +- src/main/java/org/traccar/notificators/NotificatorWeb.java | 2 +- 8 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java index e994729c0..7685eac0d 100644 --- a/src/main/java/org/traccar/notification/NotificationFormatter.java +++ b/src/main/java/org/traccar/notification/NotificationFormatter.java @@ -23,6 +23,7 @@ import org.traccar.model.Driver; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Maintenance; +import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.Server; import org.traccar.model.User; @@ -44,13 +45,15 @@ public class NotificationFormatter { this.textTemplateFormatter = textTemplateFormatter; } - public NotificationMessage formatMessage(User user, Event event, Position position, String templatePath) { + public NotificationMessage formatMessage( + Notification notification, User user, Event event, Position position, String templatePath) { Server server = cacheManager.getServer(); Device device = cacheManager.getObject(Device.class, event.getDeviceId()); VelocityContext velocityContext = textTemplateFormatter.prepareContext(server, user); + velocityContext.put("notification", notification); velocityContext.put("device", device); velocityContext.put("event", event); if (position != null) { diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index d75eb21a9..89031ba26 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -85,7 +85,7 @@ public class NotificatorFirebase implements Notificator { public void send(Notification notification, User user, Event event, Position position) throws MessageException { if (user.hasAttribute("notificationTokens")) { - var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); + var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); List registrationTokens = new ArrayList<>( Arrays.asList(user.getString("notificationTokens").split("[, ]"))); diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java index 3ab050686..11d4c5bae 100644 --- a/src/main/java/org/traccar/notificators/NotificatorMail.java +++ b/src/main/java/org/traccar/notificators/NotificatorMail.java @@ -43,7 +43,7 @@ public class NotificatorMail implements Notificator { @Override public void send(Notification notification, User user, Event event, Position position) throws MessageException { try { - var fullMessage = notificationFormatter.formatMessage(user, event, position, "full"); + var fullMessage = notificationFormatter.formatMessage(notification, user, event, position, "full"); mailManager.sendMessage(user, false, fullMessage.getSubject(), fullMessage.getBody()); } catch (MessagingException e) { throw new MessageException(e); diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 9f2a8c94d..cf4c4026b 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -63,7 +63,7 @@ public class NotificatorPushover implements Notificator { @Override public void send(Notification notification, User user, Event event, Position position) { - var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); + var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); Message message = new Message(); message.token = token; diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java index 2b6b20b1b..ce362290e 100644 --- a/src/main/java/org/traccar/notificators/NotificatorSms.java +++ b/src/main/java/org/traccar/notificators/NotificatorSms.java @@ -46,7 +46,7 @@ public class NotificatorSms implements Notificator { @Override public void send(Notification notification, User user, Event event, Position position) throws MessageException { if (user.getPhone() != null) { - var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); + var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); statisticsManager.registerSms(); smsManager.sendMessage(user.getPhone(), shortMessage.getBody(), false); } diff --git a/src/main/java/org/traccar/notificators/NotificatorTelegram.java b/src/main/java/org/traccar/notificators/NotificatorTelegram.java index c91aaa4ff..eaee32810 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTelegram.java +++ b/src/main/java/org/traccar/notificators/NotificatorTelegram.java @@ -87,7 +87,7 @@ public class NotificatorTelegram implements Notificator { @Override public void send(Notification notification, User user, Event event, Position position) { - var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); + var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); TextMessage message = new TextMessage(); message.chatId = user.getString("telegramChatId"); diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index 717742a1e..c00e3e029 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java @@ -87,7 +87,7 @@ public class NotificatorTraccar implements Notificator { public void send(org.traccar.model.Notification notification, User user, Event event, Position position) { if (user.hasAttribute("notificationTokens")) { - var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); + var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); NotificationObject item = new NotificationObject(); item.title = shortMessage.getSubject(); diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java index 3a125db3c..2b9030226 100644 --- a/src/main/java/org/traccar/notificators/NotificatorWeb.java +++ b/src/main/java/org/traccar/notificators/NotificatorWeb.java @@ -51,7 +51,7 @@ public final class NotificatorWeb implements Notificator { copy.setMaintenanceId(event.getMaintenanceId()); copy.getAttributes().putAll(event.getAttributes()); - var message = notificationFormatter.formatMessage(user, event, position, "short"); + var message = notificationFormatter.formatMessage(notification, user, event, position, "short"); copy.set("message", message.getBody()); connectionManager.updateEvent(true, user.getId(), copy); -- cgit v1.2.3 From 72cfe80fb23bb5e1d2aec2f2d2b4cfcd3662a82d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 Jan 2024 16:29:07 -0800 Subject: Configurable show unknown logs --- setup/default.xml | 1 + src/main/java/org/traccar/config/Keys.java | 11 +++++++++-- src/main/java/org/traccar/session/ConnectionManager.java | 6 ++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/setup/default.xml b/setup/default.xml index 48fd8c993..fbe63c873 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -14,6 +14,7 @@ ./modern false false + true true locationiq diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 3528dafa0..1da68e1c0 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2024 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. @@ -1247,7 +1247,7 @@ public final class Keys { /** * Maximum time period for reports in seconds. Can be useful to prevent users to request unreasonably long reports. - * By default there is no limit. + * By default, there is no limit. */ public static final ConfigKey REPORT_PERIOD_LIMIT = new LongConfigKey( "report.periodLimit", @@ -1798,6 +1798,13 @@ public final class Keys { "web.url", List.of(KeyType.CONFIG)); + /** + * Show logs from unknown devices. + */ + public static final ConfigKey WEB_SHOW_UNKNOWN_DEVICES = new BooleanConfigKey( + "web.showUnknownDevices", + List.of(KeyType.CONFIG)); + /** * Output logging to the standard terminal output instead of a log file. */ diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index a598260aa..1461c66ea 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2024 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. @@ -63,6 +63,7 @@ public class ConnectionManager implements BroadcastInterface { private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class); private final long deviceTimeout; + private final boolean showUnknownDevices; private final Map sessionsByDeviceId = new ConcurrentHashMap<>(); private final Map> sessionsByEndpoint = new ConcurrentHashMap<>(); @@ -95,6 +96,7 @@ public class ConnectionManager implements BroadcastInterface { this.broadcastService = broadcastService; this.deviceLookupService = deviceLookupService; deviceTimeout = config.getLong(Keys.STATUS_TIMEOUT); + showUnknownDevices = config.getBoolean(Keys.WEB_SHOW_UNKNOWN_DEVICES); broadcastService.registerListener(this); } @@ -344,7 +346,7 @@ public class ConnectionManager implements BroadcastInterface { var sessions = sessionsByEndpoint.getOrDefault(record.getAddress(), Map.of()); if (sessions.isEmpty()) { String unknownUniqueId = unknownByEndpoint.get(record.getAddress()); - if (unknownUniqueId != null) { + if (unknownUniqueId != null && showUnknownDevices) { record.setUniqueId(unknownUniqueId); listeners.values().stream() .flatMap(Set::stream) -- cgit v1.2.3 From acebabc690f78921a1bc10191df092c207393415 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 Jan 2024 16:36:17 -0800 Subject: Make device sharing configurable --- src/main/java/org/traccar/api/resource/DeviceResource.java | 7 +++++++ src/main/java/org/traccar/config/Keys.java | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 217ccda65..540450cbb 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -19,6 +19,8 @@ import jakarta.ws.rs.FormParam; import org.traccar.api.BaseObjectResource; import org.traccar.api.signature.TokenManager; import org.traccar.broadcast.BroadcastService; +import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.database.MediaManager; import org.traccar.helper.LogAction; import org.traccar.model.Device; @@ -60,6 +62,9 @@ import java.util.List; @Consumes(MediaType.APPLICATION_JSON) public class DeviceResource extends BaseObjectResource { + @Inject + private Config config; + @Inject private CacheManager cacheManager; @@ -212,6 +217,8 @@ public class DeviceResource extends BaseObjectResource { share.setExpirationTime(expiration); share.setTemporary(true); share.setReadonly(true); + share.setLimitCommands(!config.getBoolean(Keys.WEB_SHARE_DEVICE_COMMANDS)); + share.setDisableReports(!config.getBoolean(Keys.WEB_SHARE_DEVICE_REPORTS)); share.setId(storage.addObject(share, new Request(new Columns.Exclude("id")))); diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 1da68e1c0..e79264908 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1805,6 +1805,20 @@ public final class Keys { "web.showUnknownDevices", List.of(KeyType.CONFIG)); + /** + * Enable commands for a shared device. + */ + public static final ConfigKey WEB_SHARE_DEVICE_COMMANDS = new BooleanConfigKey( + "web.shareDevice.commands", + List.of(KeyType.CONFIG)); + + /** + * Enable reports for a shared device. + */ + public static final ConfigKey WEB_SHARE_DEVICE_REPORTS = new BooleanConfigKey( + "web.shareDevice.reports", + List.of(KeyType.CONFIG)); + /** * Output logging to the standard terminal output instead of a log file. */ -- cgit v1.2.3 From 2eb1c791693421607847962cf365847b7ba3dfe2 Mon Sep 17 00:00:00 2001 From: Theerayuttu <149565351+Theerayuttu@users.noreply.github.com> Date: Tue, 16 Jan 2024 12:29:03 +0700 Subject: Update decoder Alarm for StartekProtocol --- src/main/java/org/traccar/protocol/StartekProtocolDecoder.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java index 5cfbb36ca..71afb6ad6 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -103,6 +103,12 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { case 5: case 6: return Position.ALARM_DOOR; + case 17: + return Position.ALARM_LOW_POWER; + case 18: + return Position.ALARM_POWER_CUT; + case 19: + return Position.ALARM_POWER_RESTORED; case 39: return Position.ALARM_ACCELERATION; case 40: -- cgit v1.2.3 From 7855762df494ed113210d5d202a13de279b13dcc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 16 Jan 2024 20:45:27 -0800 Subject: Disallow device re-sharing --- src/main/java/org/traccar/api/resource/DeviceResource.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 540450cbb..d7c5a5477 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -204,6 +204,9 @@ public class DeviceResource extends BaseObjectResource { @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { User user = permissionsService.getUser(getUserId()); + if (user.getTemporary()) { + throw new SecurityException("Temporary user"); + } Device device = storage.getObject(Device.class, new Request( new Columns.All(), -- cgit v1.2.3 From 79a4cf9355b08e0b306146a94bd65adb5ed963a5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 16 Jan 2024 20:48:48 -0800 Subject: Return existing user on second share --- .../org/traccar/api/resource/DeviceResource.java | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index d7c5a5477..00a3fc5b9 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2024 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. @@ -214,18 +214,24 @@ public class DeviceResource extends BaseObjectResource { new Condition.Equals("id", deviceId), new Condition.Permission(User.class, user.getId(), Device.class)))); - User share = new User(); - share.setName(device.getName()); - share.setEmail(user.getEmail() + ":" + device.getUniqueId()); - share.setExpirationTime(expiration); - share.setTemporary(true); - share.setReadonly(true); - share.setLimitCommands(!config.getBoolean(Keys.WEB_SHARE_DEVICE_COMMANDS)); - share.setDisableReports(!config.getBoolean(Keys.WEB_SHARE_DEVICE_REPORTS)); + String shareEmail = user.getEmail() + ":" + device.getUniqueId(); + User share = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("email", shareEmail))); - share.setId(storage.addObject(share, new Request(new Columns.Exclude("id")))); + if (share == null) { + share = new User(); + share.setName(device.getName()); + share.setEmail(shareEmail); + share.setExpirationTime(expiration); + share.setTemporary(true); + share.setReadonly(true); + share.setLimitCommands(!config.getBoolean(Keys.WEB_SHARE_DEVICE_COMMANDS)); + share.setDisableReports(!config.getBoolean(Keys.WEB_SHARE_DEVICE_REPORTS)); - storage.addPermission(new Permission(User.class, share.getId(), Device.class, deviceId)); + share.setId(storage.addObject(share, new Request(new Columns.Exclude("id")))); + + storage.addPermission(new Permission(User.class, share.getId(), Device.class, deviceId)); + } return tokenManager.generateToken(share.getId(), expiration); } -- cgit v1.2.3 From 2eba0bdf8c02036d6761667f0aa022ead9587c11 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 18 Jan 2024 06:44:11 -0800 Subject: Add MT700 battery (fix #5197) --- src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java | 10 ++++++---- .../java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index 2e7cdde4e..79488acc0 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -55,7 +55,7 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_POSITION = new PatternBuilder() .text("#") - .number("(?:(dd)|x*)") // cell or voltage + .number("(?:(dd|dddd)|x*)") // cell or voltage .groupBegin() .number("#(d+),") // mcc .number("(d+),") // mnc @@ -77,7 +77,7 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_WIFI = new PatternBuilder() .text("#") - .number("(?:(dd)|x+)") // cell or voltage + .number("(?:(dd|dddd)|x+)") // cell or voltage .expression("#?") .groupBegin() .number("(d+),") // mcc @@ -179,7 +179,8 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { if (parser.matches()) { if (parser.hasNext()) { - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); + int voltage = parser.nextInt(); + position.set(Position.KEY_BATTERY, voltage > 100 ? voltage * 0.001 : voltage * 0.1); } if (parser.hasNext(4)) { @@ -211,7 +212,8 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { if (parser.matches()) { if (parser.hasNext()) { - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); + int voltage = parser.nextInt(); + position.set(Position.KEY_BATTERY, voltage > 100 ? voltage * 0.001 : voltage * 0.1); } Network network = new Network(); diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java index cdfae465c..a64a10450 100644 --- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java @@ -11,6 +11,11 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tlt2hProtocolDecoder(null)); + verifyAttribute(decoder, text( + "#867665041689485#MT700N#0000#HT#1\r\n", + "#5065$GPRMC,148996.00,A,2485.2458,N,01258.4535,E,,,151348,,,A*5D\r\n"), + Position.KEY_BATTERY, 5.065); + verifyPositions(decoder, false, text( "#862255061983166#MT700NW#0000#TOWED#1\r\n", "#4502$WIFI,051550.00,A,-50,7683C2CBC0B0,-51,7683C29BC0B0,-51,7683C2BBC0B0,-51,7483C2DBC0B0,-51,7683C2ABC0B0,221123*78\r\n")); -- cgit v1.2.3 From 22f45bd129f275b930ab2166a6b76713ca972abf Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 18 Jan 2024 07:06:46 -0800 Subject: Option to disable device sharing --- src/main/java/org/traccar/api/resource/DeviceResource.java | 3 +++ src/main/java/org/traccar/config/Keys.java | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 00a3fc5b9..c3ced9b84 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -204,6 +204,9 @@ public class DeviceResource extends BaseObjectResource { @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { User user = permissionsService.getUser(getUserId()); + if (permissionsService.getServer().getBoolean(Keys.DEVICE_SHARE_DISABLE.getKey())) { + throw new SecurityException("Sharing is disabled"); + } if (user.getTemporary()) { throw new SecurityException("Temporary user"); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index e79264908..02e684875 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -340,6 +340,13 @@ public final class Keys { List.of(KeyType.SERVER, KeyType.DEVICE), 0.0); + /** + * Disable device sharing on the server. + */ + public static final ConfigKey DEVICE_SHARE_DISABLE = new BooleanConfigKey( + "disableShare", + List.of(KeyType.SERVER)); + /** * Speed limit threshold multiplier. For example, if the speed limit is 100, but we only want to generate an event * if the speed is higher than 105, this parameter can be set to 1.05. Default multiplier is 1.0. -- cgit v1.2.3 From bb8ff944398cd79f2d576f25758ea9dd6c35d384 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 18 Jan 2024 08:30:20 -0800 Subject: iStartek serial interface support --- .../org/traccar/protocol/StartekFrameDecoder.java | 49 +++++++++ .../java/org/traccar/protocol/StartekProtocol.java | 5 +- .../traccar/protocol/StartekProtocolDecoder.java | 112 +++++++++++++++++---- .../traccar/protocol/StartekFrameDecoderTest.java | 23 +++++ .../protocol/StartekProtocolDecoderTest.java | 37 ++++--- 5 files changed, 191 insertions(+), 35 deletions(-) create mode 100644 src/main/java/org/traccar/protocol/StartekFrameDecoder.java create mode 100644 src/test/java/org/traccar/protocol/StartekFrameDecoderTest.java diff --git a/src/main/java/org/traccar/protocol/StartekFrameDecoder.java b/src/main/java/org/traccar/protocol/StartekFrameDecoder.java new file mode 100644 index 000000000..608b128cd --- /dev/null +++ b/src/main/java/org/traccar/protocol/StartekFrameDecoder.java @@ -0,0 +1,49 @@ +/* + * Copyright 2024 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.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.nio.charset.StandardCharsets; + +public class StartekFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + int lengthIndex = buf.readerIndex() + 3; + int dividerIndex = buf.indexOf(lengthIndex, buf.writerIndex(), (byte) ','); + if (dividerIndex > 0) { + int lengthOffset = dividerIndex - buf.readerIndex() + 4; + int length = lengthOffset + Integer.parseInt(buf.getCharSequence( + lengthIndex, dividerIndex - lengthIndex, StandardCharsets.US_ASCII).toString()); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/StartekProtocol.java b/src/main/java/org/traccar/protocol/StartekProtocol.java index 550545345..9c01d24e2 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocol.java +++ b/src/main/java/org/traccar/protocol/StartekProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2024 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. @@ -15,7 +15,6 @@ */ package org.traccar.protocol; -import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import org.traccar.BaseProtocol; @@ -38,7 +37,7 @@ public class StartekProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new LineBasedFrameDecoder(1100)); + pipeline.addLast(new StartekFrameDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StartekProtocolEncoder(StartekProtocol.this)); diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java index 71afb6ad6..0eeb5b2aa 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2024 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. @@ -41,12 +41,13 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { .expression(".") // index .number("d+,") // length .number("(d+),") // imei + .number("(xxx),") // type .expression("(.+)") // content .number("xx") // checksum + .text("\r\n") .compile(); private static final Pattern PATTERN_POSITION = new PatternBuilder() - .number("xxx,") // command .number("(d+),") // event .expression("([^,]+)?,") // event data .number("(dd)(dd)(dd)") // date (yyymmdd) @@ -134,26 +135,24 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { return null; } + String type = parser.next(); String content = parser.next(); - if (content.length() < 100) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_RESULT, content); - - return position; - - } else { - - return decodePosition(deviceSession, content); - + switch (type) { + case "000": + return decodePosition(deviceSession, content); + case "710": + return decodeSerial(deviceSession, content); + default: + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, null); + position.set(Position.KEY_TYPE, type); + position.set(Position.KEY_RESULT, content); + return position; } } - protected Object decodePosition(DeviceSession deviceSession, String content) throws Exception { + private Object decodePosition(DeviceSession deviceSession, String content) { Parser parser = new Parser(PATTERN_POSITION, content); if (!parser.matches()) { @@ -255,4 +254,81 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { return position; } + private Object decodeSerial(DeviceSession deviceSession, String content) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + String[] frames = content.split("\r\n"); + + for (String frame : frames) { + String[] values = frame.split(","); + int index = 0; + String type = values[index++]; + switch (type) { + case "T1": + index += 1; // speed + position.set(Position.KEY_RPM, Double.parseDouble(values[index++])); + index += 1; // fuel consumption + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index++])); + index += 4; // axel weights + index += 1; // turbo pressure + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index++])); + index += 1; // accelerator pedal + position.set("torque", Integer.parseInt(values[index++])); + index += 1; // firmware version + position.set(Position.KEY_POWER, Double.parseDouble(values[index++])); + index += 1; // coolant level + position.set("oilTemp", Double.parseDouble(values[index++])); + index += 1; // oil level + position.set(Position.KEY_THROTTLE, Double.parseDouble(values[index++])); + index += 1; // air inlet pressure + index += 1; // fuel tank secondary + index += 1; // current gear + index += 1; // seatbelt + position.set("oilPressure", Integer.parseInt(values[index++])); + index += 1; // wet tank air pressure + index += 1; // pto state + int ignition = Integer.parseInt(values[index++]); + if (ignition < 2) { + position.set(Position.KEY_IGNITION, ignition > 0); + } + index += 1; // brake pedal + position.set("catalystLevel", Double.parseDouble(values[index++])); + index += 1; // fuel type + break; + case "T2": + position.set(Position.KEY_ODOMETER, Double.parseDouble(values[index++]) * 1000); + index += 1; // total fuel + index += 1; // fuel used cruise + index += 1; // fuel used drive + index += 1; + index += 1; + index += 1; // total idle time + index += 1; // total time pto + index += 1; // time cruise + index += 1; + index += 1; + index += 1; + index += 1; + index += 1; + index += 1; // brake apps + index += 1; // clutch apps + position.set(Position.KEY_HOURS, Integer.parseInt(values[index++])); + index += 1; // time torque + position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(values[index++])); + index += 1; // total cruise control distance + position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index++])); + index += 1; // total drive time + break; + default: + break; + } + } + + return position; + } + } diff --git a/src/test/java/org/traccar/protocol/StartekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/StartekFrameDecoderTest.java new file mode 100644 index 000000000..789126471 --- /dev/null +++ b/src/test/java/org/traccar/protocol/StartekFrameDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class StartekFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new StartekFrameDecoder()); + + verifyFrame( + binary("26265c3134332c3836353439313036393537333134302c3030302c302c2c3234303130343136303031362c412c2d362e3239303633382c3130362e3830393537382c31352c302e382c302c3238322c35372c3338382c3531307c31307c303444457c30303030373442452c33312c30303030303033432c30302c30302c303444347c303141327c303030307c303030302c312c2c2c31350d0a"), + decoder.decode(null, null, binary("26265c3134332c3836353439313036393537333134302c3030302c302c2c3234303130343136303031362c412c2d362e3239303633382c3130362e3830393537382c31352c302e382c302c3238322c35372c3338382c3531307c31307c303444457c30303030373442452c33312c30303030303033432c30302c30302c303444347c303141327c303030307c303030302c312c2c2c31350d0a"))); + + verifyFrame( + binary("26265c3534362c3836353439313036313134353937302c3731302c54312c302e302c302e302c302e302c302e302c302c302c302c302c302e302c302c302e302c302c46302c302e302c302e302c302e302c302e302c302e302c302c302e302c302c302c302c302c302c312c302c302e302c30302c302e302c302e302c302e302c300d0a54322c302e3030302c302e302c393232333337323033363835343737353830382e382c393232333337323033363835343737353830382e382c343239343936373239352c343239343936373239352c302c3432393439363732392c302c302c302c302c302c302c302c302c302c302c302e302c32313437343833362e302c393232333337323033363835343737353830382e382c302c30302c302c302c302e30300d0a54352c302c302c302c302c302c302c302c302c302c302c302c302c302e302c302e302c2a2c2a2c300d0a54362c30302c30332c30302c31462c31462c31462c30452c30332c30302c30302c30302c30302c31462c31460d0a54372c302c302c302c3432393439363732392c32313437343833362e3030302c3432393439363732392c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302c302c302e3030300d0a54782c2a2c2a2c2a2c2a2c2a2c302e302c302c302c302c302c2d3132352c302c302c302c302c302c302c300d0a46330d0a"), + decoder.decode(null, null, binary("26265c3534362c3836353439313036313134353937302c3731302c54312c302e302c302e302c302e302c302e302c302c302c302c302c302e302c302c302e302c302c46302c302e302c302e302c302e302c302e302c302e302c302c302e302c302c302c302c302c302c312c302c302e302c30302c302e302c302e302c302e302c300d0a54322c302e3030302c302e302c393232333337323033363835343737353830382e382c393232333337323033363835343737353830382e382c343239343936373239352c343239343936373239352c302c3432393439363732392c302c302c302c302c302c302c302c302c302c302c302e302c32313437343833362e302c393232333337323033363835343737353830382e382c302c30302c302c302c302e30300d0a54352c302c302c302c302c302c302c302c302c302c302c302c302c302e302c302e302c2a2c2a2c300d0a54362c30302c30332c30302c31462c31462c31462c30452c30332c30302c30302c30302c30302c31462c31460d0a54372c302c302c302c3432393439363732392c32313437343833362e3030302c3432393439363732392c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302e3030302c302c302c302c302e3030300d0a54782c2a2c2a2c2a2c2a2c2a2c302e302c302c302c302c302c2d3132352c302c302c302c302c302c302c300d0a46330d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java index 94b3fd256..0d9516256 100644 --- a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java @@ -11,49 +11,58 @@ public class StartekProtocolDecoderTest extends ProtocolTest { var decoder = inject(new StartekProtocolDecoder(null)); + verifyAttributes(decoder, text( + "&&\\546,865491061145970,710,T1,0.0,0.0,0.0,0.0,0,0,0,0,0.0,0,0.0,0,F0,0.0,0.0,0.0,0.0,0.0,0,0.0,0,0,0,0,0,1,0,0.0,00,0.0,0.0,0.0,0\r\n", + "T2,0.000,0.0,9223372036854775808.8,9223372036854775808.8,4294967295,4294967295,0,429496729,0,0,0,0,0,0,0,0,0,0,0.0,21474836.0,9223372036854775808.8,0,00,0,0,0.00\r\n", + "T5,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0,*,*,0\r\n", + "T6,00,03,00,1F,1F,1F,0E,03,00,00,00,00,1F,1F\r\n", + "T7,0,0,0,429496729,21474836.000,429496729,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0,0,0.000\r\n", + "Tx,*,*,*,*,*,0.0,0,0,0,0,-125,0,0,0,0,0,0,0\r\n", + "F3\r\n")); + verifyPosition(decoder, text( - "&&l141,863911061945394,000,0,,230918072531,A,22.678598,114.045970,26,0.6,0,0,74,2286304571,460|0|249F|00001093,20,001C,00,00,04A7|019C|0000|0000,1,C0")); + "&&l141,863911061945394,000,0,,230918072531,A,22.678598,114.045970,26,0.6,0,0,74,2286304571,460|0|249F|00001093,20,001C,00,00,04A7|019C|0000|0000,1,C0\r\n")); verifyAttribute(decoder, text( - "&&s148,868703050178631,000,37,,230704040211,A,22.678565,114.046011,31,0.5,0,339,77,8,460|0|249F|0AC2620D,27,0000001D,02,00,04F2|01A1|0000|0000,129,,,,949037"), + "&&s148,868703050178631,000,37,,230704040211,A,22.678565,114.046011,31,0.5,0,339,77,8,460|0|249F|0AC2620D,27,0000001D,02,00,04F2|01A1|0000|0000,129,,,,949037\r\n"), Position.KEY_HOURS, 9490000L); verifyAttribute(decoder, text( - "&&x164,869926040743375,000,0,,220705205955,A,33.326001,44.445318,10,1.2,0,57,8,925,418|40|038C|000083CD,31,00000015,00,00,0016|016A|0000|0000,1,,,686|33||44|99|14|124|11|8D"), + "&&x164,869926040743375,000,0,,220705205955,A,33.326001,44.445318,10,1.2,0,57,8,925,418|40|038C|000083CD,31,00000015,00,00,0016|016A|0000|0000,1,,,686|33||44|99|14|124|11|8D\r\n"), Position.KEY_FUEL_CONSUMPTION, 1.1); verifyAttribute(decoder, text( - "&&R187,860294046453690,000,0,,220105160656,A,22.994986,72.499711,15,0.9,2,222,55,121135784,404|98|147B|0000376A,24,0000001F,02,00,052E|01A3|0000|0000,1,010000|020000,,853|6|10|105|73|41|125|34|52"), + "&&R187,860294046453690,000,0,,220105160656,A,22.994986,72.499711,15,0.9,2,222,55,121135784,404|98|147B|0000376A,24,0000001F,02,00,052E|01A3|0000|0000,1,010000|020000,,853|6|10|105|73|41|125|34|52\r\n"), Position.KEY_FUEL_LEVEL, null); verifyPosition(decoder, text( - "&&o142,860262050066062,000,27,,211111070826,V,28.653435,-106.077455,0,0.0,0,151,1412,918,0|0|4708|01402D19,6,0000001A,02,00,04C0|016C|0000|0000,1,,,BB")); + "&&o142,860262050066062,000,27,,211111070826,V,28.653435,-106.077455,0,0.0,0,151,1412,918,0|0|4708|01402D19,6,0000001A,02,00,04C0|016C|0000|0000,1,,,BB\r\n")); verifyPosition(decoder, text( - "&&W149,865429043319537,000,0,,211103013512,A,22.679003,114.045085,16,1.1,0,271,76,109075,460|0|249F|000010C5,19,0000003E,00,00,0A57|0168|0000|0000,1,0100000C")); + "&&W149,865429043319537,000,0,,211103013512,A,22.679003,114.045085,16,1.1,0,271,76,109075,460|0|249F|000010C5,19,0000003E,00,00,0A57|0168|0000|0000,1,0100000C\r\n")); verifyAttribute(decoder, text( - "&&:23,860262050015424,129,OKA2"), - Position.KEY_RESULT, "129,OK"); + "&&:23,860262050015424,129,OKA2\r\n"), + Position.KEY_RESULT, "OK"); verifyPosition(decoder, text( - "&&X152,861157040151686,000,18,,210907163833,A,10.232715,-67.880423,11,1.4,0,275,437,34804,734|2|3EE4|00579406,28,00000015,00,00,0000|017D|0000|0000,1,010000,,9A")); + "&&X152,861157040151686,000,18,,210907163833,A,10.232715,-67.880423,11,1.4,0,275,437,34804,734|2|3EE4|00579406,28,00000015,00,00,0000|017D|0000|0000,1,010000,,9A\r\n")); verifyPosition(decoder, text( - "&&o125,861157040554384,000,0,,210702235150,A,27.263505,153.037061,11,1.2,0,0,31,5125,505|1|7032|8C89802,20,0000002D,00,00,01E2|019DF0")); + "&&o125,861157040554384,000,0,,210702235150,A,27.263505,153.037061,11,1.2,0,0,31,5125,505|1|7032|8C89802,20,0000002D,00,00,01E2|019DF0\r\n")); verifyAttribute(decoder, text( - "&&a152,860262050010565,000,53,8F5300,210528015706,A,-38.229746,145.043446,6,1.5,0,285,84,2102994,505|1|306E|082D6101,31,0000003D,02,02,04C0|01A0|0000|0000,1,,DC"), + "&&a152,860262050010565,000,53,8F5300,210528015706,A,-38.229746,145.043446,6,1.5,0,285,84,2102994,505|1|306E|082D6101,31,0000003D,02,02,04C0|01A0|0000|0000,1,,DC\r\n"), Position.KEY_DRIVER_UNIQUE_ID, "8F5300"); verifyPosition(decoder, text( - "&&>141,860262050010565,000,36,,210407094323,V,-38.229711,145.043161,0,0.0,0,0,0,14222,505|1|306E|082D6115,24,00000039,00,00,04C0|0164|0000|0000,1,,41")); + "&&>141,860262050010565,000,36,,210407094323,V,-38.229711,145.043161,0,0.0,0,0,0,14222,505|1|306E|082D6115,24,00000039,00,00,04C0|0164|0000|0000,1,,41\r\n")); verifyPosition(decoder, text( - "&&A147,021104023195429,000,0,,180106093046,A,22.646430,114.065730,8,0.9,54,86,76,326781,460|0|27B3|0EA7,27,0000000F,02,01,04E2|018C|01C8|0000,1,0104B0,01013D|02813546")); + "&&A147,021104023195429,000,0,,180106093046,A,22.646430,114.065730,8,0.9,54,86,76,326781,460|0|27B3|0EA7,27,0000000F,02,01,04E2|018C|01C8|0000,1,0104B0,01013D|02813546\r\n")); verifyPosition(decoder, text( - "&&y139,860262050009146,000,0,,210323131512,A,22.678655,114.046223,14,1.1,0,231,71,5,460|0|249F|0099C257,28,0000003D,00,00,0493|0199|0000|0000,1,,33")); + "&&y139,860262050009146,000,0,,210323131512,A,22.678655,114.046223,14,1.1,0,231,71,5,460|0|249F|0099C257,28,0000003D,00,00,0493|0199|0000|0000,1,,33\r\n")); } -- cgit v1.2.3 From 77a2b4f5e587f648502f3a72e525b7c960e58c80 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 19 Jan 2024 07:57:49 -0800 Subject: Support NatureLink parameters --- .../traccar/protocol/HuabaoProtocolDecoder.java | 45 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index a102e9e44..2243bd982 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -471,8 +471,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x02: position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.1); break; + case 0x25: + position.set(Position.KEY_INPUT, buf.readUnsignedInt()); + break; case 0x2b: - position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); break; case 0x30: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); @@ -517,6 +521,36 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // rssi } break; + case 0x64: + buf.readUnsignedInt(); // alarm serial number + buf.readUnsignedByte(); // alarm status + position.set("adasAlarm", buf.readUnsignedByte()); + break; + case 0x65: + buf.readUnsignedInt(); // alarm serial number + buf.readUnsignedByte(); // alarm status + position.set("dmsAlarm", buf.readUnsignedByte()); + break; + case 0x70: + buf.readUnsignedInt(); // alarm serial number + buf.readUnsignedByte(); // alarm status + switch (buf.readUnsignedByte()) { + case 0x01: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 0x02: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 0x03: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + case 0x16: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + default: + break; + } + break; case 0x69: position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); break; @@ -571,7 +605,11 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { break; case 0xD4: case 0xE1: - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + if (length == 1) { + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + } else { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedInt())); + } break; case 0xD5: if (length == 2) { @@ -594,6 +632,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_MOTION, BitUtil.check(deviceStatus, 2)); position.set("cover", BitUtil.check(deviceStatus, 3)); break; + case 0xE2: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedInt() * 0.1); + break; case 0xE6: while (buf.readerIndex() < endIndex) { int sensorIndex = buf.readUnsignedByte(); -- cgit v1.2.3 From 7374a69f188918cbd247047fcb5fe09dabffa400 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 20 Jan 2024 10:20:51 -0800 Subject: Ruptela FM Pro4 attributes --- .../traccar/protocol/RuptelaProtocolDecoder.java | 42 +++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index cde626c5f..55b3c900f 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2024 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. @@ -112,6 +112,10 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 5: position.set(Position.PREFIX_IN + (id - 1), readValue(buf, length, false)); break; + case 13: + case 173: + position.set(Position.KEY_MOTION, readValue(buf, length, false) > 0); + break; case 20: position.set(Position.PREFIX_ADC + 3, readValue(buf, length, false)); break; @@ -133,6 +137,9 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 32: position.set(Position.KEY_DEVICE_TEMP, readValue(buf, length, true)); break; + case 39: + position.set(Position.KEY_ENGINE_LOAD, readValue(buf, length, true)); + break; case 65: position.set(Position.KEY_ODOMETER, readValue(buf, length, true)); break; @@ -149,9 +156,18 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); } break; + case 94: + position.set(Position.KEY_RPM, readValue(buf, length, true) * 0.25); + break; case 95: position.set(Position.KEY_OBD_SPEED, readValue(buf, length, true)); break; + case 98: + position.set("fuelRate", readValue(buf, length, true) * 100 / 255.0); + break; + case 100: + position.set(Position.KEY_FUEL_CONSUMPTION, readValue(buf, length, true) / 20.0); + break; case 134: if (readValue(buf, length, false) > 0) { position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); @@ -165,15 +181,31 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 150: position.set(Position.KEY_OPERATOR, readValue(buf, length, false)); break; - case 170: - position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0); + case 163: + position.set(Position.KEY_ODOMETER, readValue(buf, length, false) * 5); break; - case 173: - position.set(Position.KEY_MOTION, readValue(buf, length, false) > 0); + case 164: + position.set(Position.KEY_ODOMETER_TRIP, readValue(buf, length, false) * 5); + break; + case 165: + position.set(Position.KEY_OBD_SPEED, readValue(buf, length, false) / 256.0); break; + case 166: case 197: position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125); break; + case 170: + position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0); + break; + case 205: + position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, false)); + break; + case 207: + position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, false) * 0.4); + break; + case 208: + position.set(Position.KEY_FUEL_USED, readValue(buf, length, false) * 0.5); + break; case 251: case 409: position.set(Position.KEY_IGNITION, readValue(buf, length, false) > 0); -- cgit v1.2.3 From 8d2accad7071321c65055d8fb9e11d2a6a586b02 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 20 Jan 2024 10:35:13 -0800 Subject: Missing Meitrack T399 parameters --- src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index c37d1fe47..965c8ee0d 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -465,6 +465,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x16: position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE() * 0.01); break; + case 0x17: + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE() * 0.01); + break; case 0x19: position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); break; -- cgit v1.2.3 From d4d66200bf1de4a1932765690ffb9eedd58f0900 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 21 Jan 2024 08:17:47 -0800 Subject: Improve sharing permissions --- src/main/java/org/traccar/api/resource/DeviceResource.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index c3ced9b84..8e634232a 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -228,8 +228,8 @@ public class DeviceResource extends BaseObjectResource { share.setExpirationTime(expiration); share.setTemporary(true); share.setReadonly(true); - share.setLimitCommands(!config.getBoolean(Keys.WEB_SHARE_DEVICE_COMMANDS)); - share.setDisableReports(!config.getBoolean(Keys.WEB_SHARE_DEVICE_REPORTS)); + share.setLimitCommands(user.getLimitCommands() || !config.getBoolean(Keys.WEB_SHARE_DEVICE_COMMANDS)); + share.setDisableReports(user.getDisableReports() || !config.getBoolean(Keys.WEB_SHARE_DEVICE_REPORTS)); share.setId(storage.addObject(share, new Request(new Columns.Exclude("id")))); -- cgit v1.2.3 From 4d9d78496a0260c6cb43211065a8aafe8cc7e7a9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 21 Jan 2024 08:21:01 -0800 Subject: Improve sharing expiration limit --- src/main/java/org/traccar/api/resource/DeviceResource.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 8e634232a..89bba7237 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -210,6 +210,9 @@ public class DeviceResource extends BaseObjectResource { if (user.getTemporary()) { throw new SecurityException("Temporary user"); } + if (user.getExpirationTime() != null && user.getExpirationTime().before(expiration)) { + expiration = user.getExpirationTime(); + } Device device = storage.getObject(Device.class, new Request( new Columns.All(), -- cgit v1.2.3 From 29b8caa047b3b1468eb8b21e76f5df8b5c2f6ddb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 25 Jan 2024 08:11:32 -0800 Subject: Initialization grace period (fix #5258) --- src/main/java/org/traccar/Main.java | 32 ++++++---------- .../java/org/traccar/schedule/ScheduleManager.java | 11 +++--- .../java/org/traccar/schedule/TaskClearStatus.java | 43 ++++++++++++++++++++++ .../java/org/traccar/schedule/TaskHealthCheck.java | 24 ++++++++---- 4 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 src/main/java/org/traccar/schedule/TaskClearStatus.java diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index e34fbb72a..33fcf654f 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -20,10 +20,8 @@ import com.google.inject.Injector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.broadcast.BroadcastService; -import org.traccar.helper.model.DeviceUtil; import org.traccar.schedule.ScheduleManager; import org.traccar.storage.DatabaseModule; -import org.traccar.storage.Storage; import org.traccar.web.WebModule; import org.traccar.web.WebServer; @@ -33,10 +31,9 @@ import java.lang.management.MemoryMXBean; import java.lang.management.OperatingSystemMXBean; import java.lang.management.RuntimeMXBean; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; public final class Main { @@ -70,8 +67,7 @@ public final class Main { + " heap: " + memoryBean.getHeapMemoryUsage().getMax() / (1024 * 1024) + "mb" + " non-heap: " + memoryBean.getNonHeapMemoryUsage().getMax() / (1024 * 1024) + "mb"); - LOGGER.info("Character encoding: " - + System.getProperty("file.encoding") + " charset: " + Charset.defaultCharset()); + LOGGER.info("Character encoding: " + Charset.defaultCharset().displayName()); } catch (Exception error) { LOGGER.warn("Failed to get system info"); @@ -122,18 +118,14 @@ public final class Main { LOGGER.info("Version: " + Main.class.getPackage().getImplementationVersion()); LOGGER.info("Starting server..."); - if (injector.getInstance(BroadcastService.class).singleInstance()) { - DeviceUtil.resetStatus(injector.getInstance(Storage.class)); - } - - var services = Stream.of( - ServerManager.class, WebServer.class, ScheduleManager.class, BroadcastService.class) - .map(injector::getInstance) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - for (var service : services) { - service.start(); + var services = new ArrayList(); + for (var clazz : List.of( + ScheduleManager.class, ServerManager.class, WebServer.class, BroadcastService.class)) { + var service = injector.getInstance(clazz); + if (service != null) { + service.start(); + services.add(service); + } } Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOGGER.error("Thread exception", e)); diff --git a/src/main/java/org/traccar/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java index 3756d955b..742428fd8 100644 --- a/src/main/java/org/traccar/schedule/ScheduleManager.java +++ b/src/main/java/org/traccar/schedule/ScheduleManager.java @@ -20,9 +20,9 @@ import org.traccar.LifecycleObject; import jakarta.inject.Inject; import jakarta.inject.Singleton; -import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.stream.Stream; @Singleton public class ScheduleManager implements LifecycleObject { @@ -38,14 +38,15 @@ public class ScheduleManager implements LifecycleObject { @Override public void start() { executor = Executors.newSingleThreadScheduledExecutor(); - var tasks = List.of( + Stream.of( + TaskHealthCheck.class, + TaskClearStatus.class, TaskExpirations.class, TaskDeleteTemporary.class, TaskReports.class, TaskDeviceInactivityCheck.class, - TaskWebSocketKeepalive.class, - TaskHealthCheck.class); - tasks.forEach(task -> injector.getInstance(task).schedule(executor)); + TaskWebSocketKeepalive.class) + .forEachOrdered(task -> injector.getInstance(task).schedule(executor)); } @Override diff --git a/src/main/java/org/traccar/schedule/TaskClearStatus.java b/src/main/java/org/traccar/schedule/TaskClearStatus.java new file mode 100644 index 000000000..78fecc0ea --- /dev/null +++ b/src/main/java/org/traccar/schedule/TaskClearStatus.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024 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.schedule; + +import jakarta.inject.Inject; +import org.traccar.broadcast.BroadcastService; +import org.traccar.helper.model.DeviceUtil; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; + +import java.util.concurrent.ScheduledExecutorService; + +public class TaskClearStatus implements ScheduleTask { + + @Inject + public TaskClearStatus(BroadcastService broadcastService, Storage storage) throws StorageException { + if (broadcastService.singleInstance()) { + DeviceUtil.resetStatus(storage); + } + } + + @Override + public void schedule(ScheduledExecutorService executor) { + } + + @Override + public void run() { + } + +} diff --git a/src/main/java/org/traccar/schedule/TaskHealthCheck.java b/src/main/java/org/traccar/schedule/TaskHealthCheck.java index abdc5af48..a60935f18 100644 --- a/src/main/java/org/traccar/schedule/TaskHealthCheck.java +++ b/src/main/java/org/traccar/schedule/TaskHealthCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2024 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. @@ -34,6 +34,8 @@ public class TaskHealthCheck implements ScheduleTask { private final Config config; private final Client client; + private final long gracePeriod = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1); + private SystemD systemD; private boolean enabled; @@ -77,14 +79,22 @@ public class TaskHealthCheck implements ScheduleTask { @Override public void run() { LOGGER.debug("Health check running"); - int status = client.target(getUrl()).request().get().getStatus(); - if (status == 200) { - int result = systemD.sd_notify(0, "WATCHDOG=1"); - if (result < 0) { - LOGGER.warn("Health check notify error {}", result); + if (System.currentTimeMillis() > gracePeriod) { + int status = client.target(getUrl()).request().get().getStatus(); + if (status == 200) { + notifyWatchdog(); + } else { + LOGGER.warn("Health check failed with status {}", status); } } else { - LOGGER.warn("Health check failed with status {}", status); + notifyWatchdog(); + } + } + + private void notifyWatchdog() { + int result = systemD.sd_notify(0, "WATCHDOG=1"); + if (result < 0) { + LOGGER.warn("Health check notify error {}", result); } } -- cgit v1.2.3 From e5c21c80df6310ea29209dc037ba82be5fbf441e Mon Sep 17 00:00:00 2001 From: Sanjeewa Vithanage Date: Fri, 26 Jan 2024 17:03:02 +0200 Subject: analog input voltage decode --- src/main/java/org/traccar/protocol/UproProtocolDecoder.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index ed714e464..debb85365 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -310,6 +310,11 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { position.set("serial", data.toString(StandardCharsets.US_ASCII).substring(3)); } break; + case 'd': + if (data.readableBytes() > 3) { + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(data.readSlice(5).toString(StandardCharsets.US_ASCII)) * 0.01); + } + break; default: break; } -- cgit v1.2.3 From 97f0ed1d19bc638ff5866bcdf5163f89801859b0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 26 Jan 2024 07:23:13 -0800 Subject: Add MD500S test case --- src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 24dc9d18e..74a180b11 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "24246D3230312C3836393430393036323730323834332C4343452C000000000100A7002A000D05010626070914001502930194009500960097629D209E63A1640E0824000956000A07000B2A001606001704001901001A0E0B91280092280099EF049C52009F1B004023000C0215B9F2FF035855F506041E0F142D0C01708C010D748AC2001C012000009A000000009BD0623E02A0889FF201A2D61A0000A542020000FEF4A3D50900030E0CFE010A007F466FFC0000000049090401000000000000004B0501010232472A44360D0A"), + Position.KEY_HOURS, 644515 * 60000L); + verifyAttribute(decoder, binary( "2424593136312c3836323039303035303031363139332c4343452c0000000001007f0017000705010607071714001500fe69601b00070800000971000a13000b19001605001acc0440230006029779570103eb5bcc06041ff0e8290c430100000d780400001c01000000030e0ccc010000922781abb90ca4fffe731e0109746e6873656e736f72ac233f6e219064051b753b00000000000000004b060101034c54452a42380d0a"), "tagName", "tnhsensor"); -- cgit v1.2.3 From b82bacce74f38d34cbf16749ca23961eb0f8a919 Mon Sep 17 00:00:00 2001 From: Sanjeewa Vithanage Date: Fri, 26 Jan 2024 17:32:50 +0200 Subject: Line wrapper --- src/main/java/org/traccar/protocol/UproProtocolDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index debb85365..2f88d803c 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -312,7 +312,8 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { break; case 'd': if (data.readableBytes() > 3) { - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(data.readSlice(5).toString(StandardCharsets.US_ASCII)) * 0.01); + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(data.readSlice(5). + toString(StandardCharsets.US_ASCII)) * 0.01); } break; default: -- cgit v1.2.3 From 29d50ef59b59026925b580c72c27aed09ab78500 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 26 Jan 2024 18:03:01 -0800 Subject: Fix Ruptela fuel level --- src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 55b3c900f..402262348 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -163,7 +163,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_OBD_SPEED, readValue(buf, length, true)); break; case 98: - position.set("fuelRate", readValue(buf, length, true) * 100 / 255.0); + position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, true) * 100 / 255.0); break; case 100: position.set(Position.KEY_FUEL_CONSUMPTION, readValue(buf, length, true) / 20.0); -- cgit v1.2.3 From d1473309d3338c2f247e4d80f5b1076da4882253 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 27 Jan 2024 07:46:33 -0800 Subject: Update version number --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 41baa7f89..3677f8f94 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.11", + "Implementation-Version": "5.12", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 68258dcb5..2ccee1c3e 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.11 +AppVersion=5.12 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index 9268e1a0d..b2209a20e 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.11", + "version": "5.12", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From b098be7f6245dcd2c00cc8457174e9fe7733d3b2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 27 Jan 2024 08:18:22 -0800 Subject: Update submodule commit --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index d1a9c0857..42db1a41c 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit d1a9c08571683184ce10b7db5890e2a75bf6179c +Subproject commit 42db1a41cbf733ea4f82c86e5d45a6fbccc8b8f2 -- cgit v1.2.3 From 34b507dbe268c6aec2f20e9ec3c3f9e243187c3e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 27 Jan 2024 14:41:05 -0800 Subject: Initial FleetGuide implementation --- setup/default.xml | 1 + .../org/traccar/protocol/FleetGuideProtocol.java | 36 ++++++++ .../protocol/FleetGuideProtocolDecoder.java | 98 ++++++++++++++++++++++ .../protocol/FleetGuideProtocolDecoderTest.java | 20 +++++ 4 files changed, 155 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/FleetGuideProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index fbe63c873..b89e3ebef 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -296,5 +296,6 @@ 5251 5252 5253 + 5254 diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocol.java b/src/main/java/org/traccar/protocol/FleetGuideProtocol.java new file mode 100644 index 000000000..46611c25c --- /dev/null +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocol.java @@ -0,0 +1,36 @@ +/* + * Copyright 2024 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 jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class FleetGuideProtocol extends BaseProtocol { + + @Inject + public FleetGuideProtocol(Config config) { + addServer(new TrackerServer(config, getName(), true) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new FleetGuideProtocolDecoder(FleetGuideProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java new file mode 100644 index 000000000..d63187921 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -0,0 +1,98 @@ +/* + * Copyright 2024 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.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.session.DeviceSession; + +import java.lang.reflect.Method; +import java.net.SocketAddress; + +public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { + + public FleetGuideProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_DATA = 0x10; + public static final int MSG_HEARTBEAT = 0x1A; + public static final int MSG_RESPONSE = 0x1C; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // signature + int options = buf.readUnsignedShort(); + int length = BitUtil.to(options, 11); + + DeviceSession deviceSession; + if (BitUtil.check(options, 11)) { + deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + } + if (deviceSession == null) { + return null; + } + + int type; + if (BitUtil.check(options, 12)) { + type = BitUtil.to(buf.readUnsignedByte(), 4); + } else { + type = 0; + } + + if (BitUtil.check(options, 13)) { + buf.readUnsignedShort(); // acknowledgement + } + + ByteBuf data; + if (BitUtil.check(options, 14)) { + data = decompress(buf.readSlice(length)); + } else { + data = buf.readRetainedSlice(length); + } + + data.release(); + + return null; + } + + private ByteBuf decompress(ByteBuf input) throws ReflectiveOperationException { + + Class clazz = Class.forName("io.netty.handler.codec.compression.FastLz"); + Method method = clazz.getDeclaredMethod( + "decompress", ByteBuf.class, int.class, int.class, ByteBuf.class, int.class, int.class); + + ByteBuf output = Unpooled.buffer(); + int result = (Integer) method.invoke( + null, input, input.readerIndex(), input.readableBytes(), output, 0, Integer.MAX_VALUE); + if (result <= 0) { + throw new IllegalArgumentException("FastLz decompression failed"); + } + + return output; + } + +} diff --git a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java new file mode 100644 index 000000000..010f0d649 --- /dev/null +++ b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java @@ -0,0 +1,20 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +@Disabled +public class FleetGuideProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new FleetGuideProtocolDecoder(null)); + + verifyPosition(decoder, binary( + "539e598f8a020003020700e378351ac39f040c04ffa92e806a28a13b1f00b638030c000067052c06ffffffff033006808001180003200100000700e478351ac40204303dab2e80cb27a13b1c00ac40021b30e778351ac502043082a72e8054020530bf30021b30e978351ac69f0d0c0433a72e80c123a13b2000df3807002579351ac79f06020a170000df28021b476179351ac8020f30021c81279d79351ac9020f30021c8207d979351aca020f30021c8157157a351acb022b8140517a351acc022b608d7a351acd022b60c97a351ace022b30057b351acf022b30417b351ad0022b307d7b351ad1020f3048021b30b97b351ad2020f3070030c004066021630f57b351ad30213841080021730317c351ad4021330c00217306d7c351ad5020f3050021b30a97c351ad602138170021830e57c351ad7020f3058021b30217d351ad8021385500218305d7d351ad9022b8110997d351ada022b8170d57d351adb022b30117e351adc020f3068030ce184680216304d7e351add020f3060030ce34469021630897e351ade021260e4021830c57e351adf021230e5021830017f351ae002293022f2")); + + } + +} -- cgit v1.2.3 From 7577626863a370056169386860a3e8805f45663b Mon Sep 17 00:00:00 2001 From: Sanjeewa Vithanage Date: Sun, 28 Jan 2024 07:36:38 +0200 Subject: test decode --- src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java index c99166374..ca2944c04 100644 --- a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java @@ -83,6 +83,10 @@ public class UproProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, buffer( "*AI2000905300036,AD1&A1703054913231101844949860000251115&B0500000000&C0;4?72:9&F0000")); + verifyAttribute(decoder, buffer( + "*HQ200862312328000001,AD1&A1520441548253003503696640017270124&B0000000000&C00000117&F0000&R2118&N01&V0125&X(J01E0)&K00300&Z000&d01286"), + Position.PREFIX_ADC + 1, 12.86); + } } -- cgit v1.2.3 From 2f49889aa496524b298f764e18f8016e74efab87 Mon Sep 17 00:00:00 2001 From: Sanjeewa Vithanage Date: Sun, 28 Jan 2024 09:28:34 +0200 Subject: fixed with unwanted decimal points ("adc1":12.870000000000001) --- src/main/java/org/traccar/protocol/UproProtocolDecoder.java | 6 ++---- src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index 2f88d803c..1167f568c 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -311,10 +311,8 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { } break; case 'd': - if (data.readableBytes() > 3) { - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(data.readSlice(5). - toString(StandardCharsets.US_ASCII)) * 0.01); - } + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(data. + toString(StandardCharsets.US_ASCII))/100.0); break; default: break; diff --git a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java index ca2944c04..f070c6201 100644 --- a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java @@ -87,6 +87,10 @@ public class UproProtocolDecoderTest extends ProtocolTest { "*HQ200862312328000001,AD1&A1520441548253003503696640017270124&B0000000000&C00000117&F0000&R2118&N01&V0125&X(J01E0)&K00300&Z000&d01286"), Position.PREFIX_ADC + 1, 12.86); + verifyAttribute(decoder, buffer( + "*HQ200862312328000001,BA&A1520461548253003503696640017270124&B0000000000&C00000117&F0000&R2218&N01&V0125&X(J01E0)&K00300&Z000&d01287"), + Position.PREFIX_ADC + 1, 12.87); + } } -- cgit v1.2.3 From 52dcedfe60e5b9468db16e7d72048595bcdeb98f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 28 Jan 2024 08:15:46 -0800 Subject: Support time maintenance --- .../handler/events/MaintenanceEventHandler.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java index 6c4271ce2..2fa2e8869 100644 --- a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -49,8 +49,8 @@ public class MaintenanceEventHandler extends BaseEventHandler { Map events = new HashMap<>(); for (Maintenance maintenance : cacheManager.getDeviceObjects(position.getDeviceId(), Maintenance.class)) { if (maintenance.getPeriod() != 0) { - double oldValue = lastPosition.getDouble(maintenance.getType()); - double newValue = position.getDouble(maintenance.getType()); + double oldValue = getValue(lastPosition, maintenance.getType()); + double newValue = getValue(position, maintenance.getType()); if (oldValue != 0.0 && newValue != 0.0 && newValue >= maintenance.getStart()) { if (oldValue < maintenance.getStart() || (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod()) @@ -67,4 +67,17 @@ public class MaintenanceEventHandler extends BaseEventHandler { return events; } + private double getValue(Position position, String type) { + switch (type) { + case "serverTime": + return position.getServerTime().getTime(); + case "deviceTime": + return position.getDeviceTime().getTime(); + case "fixTime": + return position.getFixTime().getTime(); + default: + return position.getDouble(type); + } + } + } -- cgit v1.2.3 From 04a99c14fc2840f78e988d66c150807abae8bf79 Mon Sep 17 00:00:00 2001 From: Sanjeewa Vithanage Date: Mon, 29 Jan 2024 12:11:02 +0200 Subject: fix styling --- src/main/java/org/traccar/protocol/UproProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index 1167f568c..915f5adfe 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -311,8 +311,8 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { } break; case 'd': - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(data. - toString(StandardCharsets.US_ASCII))/100.0); + position.set(Position.PREFIX_ADC + 1, + (Integer.parseInt(data.toString(StandardCharsets.US_ASCII)) / 100.0)); break; default: break; -- cgit v1.2.3 From 7726ea879700329b62700528ad495f4f1c515dd0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 29 Jan 2024 06:48:30 -0800 Subject: Remove unnecessary brackets --- src/main/java/org/traccar/protocol/UproProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index 915f5adfe..8d2e5de0a 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -312,7 +312,7 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { break; case 'd': position.set(Position.PREFIX_ADC + 1, - (Integer.parseInt(data.toString(StandardCharsets.US_ASCII)) / 100.0)); + Integer.parseInt(data.toString(StandardCharsets.US_ASCII)) / 100.0); break; default: break; -- cgit v1.2.3 From b7d405e9d5cc64b88dfd09cd43d621338f550d68 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 29 Jan 2024 20:43:38 -0800 Subject: Minor FleetGuide updates --- src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java index d63187921..4e5de2b3e 100644 --- a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -43,12 +43,12 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; buf.readUnsignedByte(); // signature - int options = buf.readUnsignedShort(); + int options = buf.readUnsignedShortLE(); int length = BitUtil.to(options, 11); DeviceSession deviceSession; if (BitUtil.check(options, 11)) { - deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); + deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedIntLE())); } else { deviceSession = getDeviceSession(channel, remoteAddress); } @@ -64,7 +64,7 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { } if (BitUtil.check(options, 13)) { - buf.readUnsignedShort(); // acknowledgement + buf.readUnsignedShortLE(); // acknowledgement } ByteBuf data; @@ -84,6 +84,7 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { Class clazz = Class.forName("io.netty.handler.codec.compression.FastLz"); Method method = clazz.getDeclaredMethod( "decompress", ByteBuf.class, int.class, int.class, ByteBuf.class, int.class, int.class); + method.setAccessible(true); ByteBuf output = Unpooled.buffer(); int result = (Integer) method.invoke( -- cgit v1.2.3 From 5c1a520850acced42cf81b3974134067182b6a99 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 30 Jan 2024 17:35:37 -0800 Subject: Fix Ruptela unsigned parameters --- .../java/org/traccar/protocol/RuptelaProtocolDecoder.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 402262348..e1efb5757 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -138,10 +138,10 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_DEVICE_TEMP, readValue(buf, length, true)); break; case 39: - position.set(Position.KEY_ENGINE_LOAD, readValue(buf, length, true)); + position.set(Position.KEY_ENGINE_LOAD, readValue(buf, length, false)); break; case 65: - position.set(Position.KEY_ODOMETER, readValue(buf, length, true)); + position.set(Position.KEY_ODOMETER, readValue(buf, length, false)); break; case 74: position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1); @@ -157,16 +157,16 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { } break; case 94: - position.set(Position.KEY_RPM, readValue(buf, length, true) * 0.25); + position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.25); break; case 95: - position.set(Position.KEY_OBD_SPEED, readValue(buf, length, true)); + position.set(Position.KEY_OBD_SPEED, readValue(buf, length, false)); break; case 98: - position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, true) * 100 / 255.0); + position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, false) * 100 / 255.0); break; case 100: - position.set(Position.KEY_FUEL_CONSUMPTION, readValue(buf, length, true) / 20.0); + position.set(Position.KEY_FUEL_CONSUMPTION, readValue(buf, length, false) / 20.0); break; case 134: if (readValue(buf, length, false) > 0) { @@ -226,7 +226,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { } break; case 645: - position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, true) * 1000); + position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, false) * 1000); break; case 758: if (readValue(buf, length, false) == 1) { -- cgit v1.2.3 From cff42765e3ab39dccb73ea7d49f4b6270fe9931a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 31 Jan 2024 08:24:52 -0800 Subject: Add LZ77 decompression algorithm --- .../protocol/FleetGuideProtocolDecoder.java | 49 ++++++++++++++++------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java index 4e5de2b3e..94d837145 100644 --- a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -23,7 +23,6 @@ import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.session.DeviceSession; -import java.lang.reflect.Method; import java.net.SocketAddress; public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { @@ -79,21 +78,47 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { return null; } - private ByteBuf decompress(ByteBuf input) throws ReflectiveOperationException { + private int readVarSize(ByteBuf buf) { + int b; + int y = 0; + do { + b = buf.readUnsignedByte(); + y = (y << 7) | (b & 0x0000007f); + } while ((b & 0x00000080) > 0); - Class clazz = Class.forName("io.netty.handler.codec.compression.FastLz"); - Method method = clazz.getDeclaredMethod( - "decompress", ByteBuf.class, int.class, int.class, ByteBuf.class, int.class, int.class); - method.setAccessible(true); + return y; + } + + private ByteBuf decompress(ByteBuf in) { + + ByteBuf out = Unpooled.buffer(); - ByteBuf output = Unpooled.buffer(); - int result = (Integer) method.invoke( - null, input, input.readerIndex(), input.readableBytes(), output, 0, Integer.MAX_VALUE); - if (result <= 0) { - throw new IllegalArgumentException("FastLz decompression failed"); + if (in.readableBytes() < 1) { + return out; } - return output; + int marker = in.readUnsignedByte(); + + do { + int symbol = in.readUnsignedByte(); + if (symbol == marker) { + if (in.getUnsignedByte(in.readerIndex()) == 0) { + out.writeByte(marker); + in.skipBytes(1); + } else { + int length = readVarSize(in); + int offset = readVarSize(in); + + for (int i = 0; i < length; i++) { + out.writeByte(out.getUnsignedByte(out.writerIndex() - offset)); + } + } + } else { + out.writeByte(symbol); + } + } while (in.isReadable()); + + return out; } } -- cgit v1.2.3 From 7d82b0f88197f8ebfcef949abec4ddca07d9ed87 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 1 Feb 2024 07:49:28 -0800 Subject: Decode FleetGuide locations --- .../protocol/FleetGuideProtocolDecoder.java | 77 +++++++++++++++++++++- .../protocol/FleetGuideProtocolDecoderTest.java | 4 +- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java index 94d837145..9fddec922 100644 --- a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -21,9 +21,16 @@ import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.Protocol; import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; import org.traccar.session.DeviceSession; import java.net.SocketAddress; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { @@ -73,9 +80,77 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { data = buf.readRetainedSlice(length); } + List positions = new LinkedList<>(); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + Set recordTypes = new HashSet<>(); + + while (data.isReadable()) { + + int recordHeader = data.readUnsignedShortLE(); + int recordLength = BitUtil.to(recordHeader, 10); + int recordType = BitUtil.from(recordHeader, 10); + int recordEndIndex = data.readerIndex() + recordLength; + + if (recordTypes.contains(recordType)) { + positions.add(processPosition(position)); + position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + recordTypes.clear(); + } + recordTypes.add(recordType); + + switch (recordType) { + case 0: + position.setTime(new Date((data.readUnsignedIntLE() + 1262304000) * 1000)); // since 2010-01-01 + break; + case 1: + position.setLatitude(data.readUnsignedIntLE() * 90.0 / 0xFFFFFFFFL); + position.setLongitude(data.readUnsignedIntLE() * 180.0 / 0xFFFFFFFFL); + int speed = data.readUnsignedShortLE(); + position.setSpeed(UnitsConverter.knotsFromKph(BitUtil.to(speed, 14) * 0.1)); + if (BitUtil.check(speed, 14)) { + position.setLatitude(-position.getLatitude()); + } + if (BitUtil.check(speed, 15)) { + position.setLongitude(-position.getLongitude()); + } + int course = data.readUnsignedShortLE(); + position.setSpeed(BitUtil.to(course, 9)); + int motion = BitUtil.between(course, 9, 11); + if (motion > 0) { + position.set(Position.KEY_MOTION, motion == 1); + } + position.set(Position.KEY_SATELLITES, BitUtil.from(course, 11)); + int altitude = data.readUnsignedShortLE(); + position.setAltitude(BitUtil.to(altitude, 14)); + if (BitUtil.check(altitude, 14)) { + position.setAltitude(-position.getAltitude()); + } + break; + default: + break; + } + + data.readerIndex(recordEndIndex); + + } + data.release(); - return null; + return positions.isEmpty() ? null : positions; + } + + private Position processPosition(Position position) { + if (position.getFixTime() == null) { + position.setTime(new Date()); + } + if (!position.getAttributes().containsKey(Position.KEY_SATELLITES)) { + getLastLocation(position, null); + } + return position; } private int readVarSize(ByteBuf buf) { diff --git a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java index 010f0d649..34b15d14b 100644 --- a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java @@ -1,10 +1,8 @@ package org.traccar.protocol; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; -@Disabled public class FleetGuideProtocolDecoderTest extends ProtocolTest { @Test @@ -12,7 +10,7 @@ public class FleetGuideProtocolDecoderTest extends ProtocolTest { var decoder = inject(new FleetGuideProtocolDecoder(null)); - verifyPosition(decoder, binary( + verifyPositions(decoder, binary( "539e598f8a020003020700e378351ac39f040c04ffa92e806a28a13b1f00b638030c000067052c06ffffffff033006808001180003200100000700e478351ac40204303dab2e80cb27a13b1c00ac40021b30e778351ac502043082a72e8054020530bf30021b30e978351ac69f0d0c0433a72e80c123a13b2000df3807002579351ac79f06020a170000df28021b476179351ac8020f30021c81279d79351ac9020f30021c8207d979351aca020f30021c8157157a351acb022b8140517a351acc022b608d7a351acd022b60c97a351ace022b30057b351acf022b30417b351ad0022b307d7b351ad1020f3048021b30b97b351ad2020f3070030c004066021630f57b351ad30213841080021730317c351ad4021330c00217306d7c351ad5020f3050021b30a97c351ad602138170021830e57c351ad7020f3058021b30217d351ad8021385500218305d7d351ad9022b8110997d351ada022b8170d57d351adb022b30117e351adc020f3068030ce184680216304d7e351add020f3060030ce34469021630897e351ade021260e4021830c57e351adf021230e5021830017f351ae002293022f2")); } -- cgit v1.2.3 From 1e0cc806b7386680492cb3b6b266bb4f958b2f1e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 1 Feb 2024 09:14:28 -0800 Subject: Decode Eview Pet configuration --- src/main/java/org/traccar/helper/BufferUtil.java | 4 + .../protocol/Minifinder2ProtocolDecoder.java | 172 ++++++++++++++++++++- .../protocol/Minifinder2ProtocolDecoderTest.java | 3 + 3 files changed, 178 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java index 12c31ba9d..b453c437f 100644 --- a/src/main/java/org/traccar/helper/BufferUtil.java +++ b/src/main/java/org/traccar/helper/BufferUtil.java @@ -83,4 +83,8 @@ public final class BufferUtil { return printable; } + public static String readString(ByteBuf buf, int length) { + return buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + } + } diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 57ceab4c7..64373e344 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2024 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. @@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -315,6 +316,10 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { return positions; + } else if (type == MSG_CONFIGURATION) { + + return decodeConfiguration(channel, remoteAddress, buf); + } else if (type == MSG_RESPONSE) { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); @@ -337,4 +342,169 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { return null; } + private Position decodeConfiguration(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + while (buf.isReadable()) { + int length = buf.readUnsignedByte() - 1; + int endIndex = buf.readerIndex() + length + 1; + int key = buf.readUnsignedByte(); + + switch (key) { + case 0x01: + position.set("moduleNumber", buf.readUnsignedInt()); + break; + case 0x02: + position.set(Position.KEY_VERSION_FW, String.valueOf(buf.readUnsignedInt())); + break; + case 0x03: + position.set("imei", buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + break; + case 0x04: + position.set(Position.KEY_ICCID, BufferUtil.readString(buf, length)); + break; + case 0x05: + position.set("bleMac", ByteBufUtil.hexDump(buf.readSlice(length))); + break; + case 0x06: + position.set("settingTime", buf.readUnsignedInt()); + break; + case 0x07: + position.set("runTimes", buf.readUnsignedInt()); + break; + case 0x0A: + position.set("interval", buf.readUnsignedMedium()); + position.set("petMode", buf.readUnsignedByte()); + break; + case 0x0D: + position.set("passwordProtect", buf.readUnsignedInt()); + break; + case 0x0E: + position.set("timeZone", (int) buf.readByte()); + break; + case 0x0F: + position.set("enableControl", buf.readUnsignedInt()); + break; + case 0x13: + position.set("deviceName", BufferUtil.readString(buf, length)); + break; + case 0x14: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + break; + case 0x15: + position.set("bleLatitude", buf.readIntLE() * 0.0000001); + position.set("bleLongitude", buf.readIntLE() * 0.0000001); + position.set("bleLocation", BufferUtil.readString(buf, length - 8)); + break; + case 0x17: + position.set("gpsUrl", BufferUtil.readString(buf, length)); + break; + case 0x18: + position.set("lbsUrl", BufferUtil.readString(buf, length)); + break; + case 0x1A: + position.set("firmware", BufferUtil.readString(buf, length)); + break; + case 0x1B: + position.set("gsmModule", BufferUtil.readString(buf, length)); + break; + case 0x1D: + position.set("agpsUpdate", buf.readUnsignedByte()); + position.set("agpsLatitude", buf.readIntLE() * 0.0000001); + position.set("agpsLongitude", buf.readIntLE() * 0.0000001); + break; + case 0x30: + position.set("numberFlag", buf.readUnsignedByte()); + position.set("number", BufferUtil.readString(buf, length - 1)); + break; + case 0x31: + position.set("prefixFlag", buf.readUnsignedByte()); + position.set("prefix", BufferUtil.readString(buf, length - 1)); + break; + case 0x33: + position.set("phoneSwitches", buf.readUnsignedByte()); + break; + case 0x40: + position.set("apn", BufferUtil.readString(buf, length)); + break; + case 0x41: + position.set("apnUser", BufferUtil.readString(buf, length)); + break; + case 0x42: + position.set("apnPassword", BufferUtil.readString(buf, length)); + break; + case 0x43: + buf.readUnsignedByte(); // flag + position.set("port", buf.readUnsignedShort()); + position.set("server", BufferUtil.readString(buf, length - 3)); + break; + case 0x44: + position.set("heartbeatInterval", buf.readUnsignedInt()); + position.set("uploadInterval", buf.readUnsignedInt()); + position.set("uploadLazyInterval", buf.readUnsignedInt()); + break; + case 0x47: + position.set("deviceId", BufferUtil.readString(buf, length)); + break; + case 0x4E: + position.set("gsmBand", buf.readUnsignedByte()); + break; + case 0x50: + position.set("powerAlert", buf.readUnsignedInt()); + break; + case 0x51: + position.set("geoAlert", buf.readUnsignedInt()); + break; + case 0x53: + position.set("motionAlert", buf.readUnsignedInt()); + break; + case 0x5C: + position.set("barkLevel", buf.readUnsignedByte()); + position.set("barkInterval", buf.readUnsignedInt()); + break; + case 0x61: + position.set("msisdn", BufferUtil.readString(buf, length)); + break; + case 0x62: + position.set("wifiWhitelist", buf.readUnsignedByte()); + position.set("wifiWhitelistMac", ByteBufUtil.hexDump(buf.readSlice(6))); + break; + case 0x64: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set("networkBand", buf.readUnsignedInt()); + position.set(Position.KEY_OPERATOR, BufferUtil.readString(buf, length - 5)); + break; + case 0x65: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set("networkStatus", buf.readUnsignedByte()); + position.set("serverStatus", buf.readUnsignedByte()); + position.set("networkPlmn", ByteBufUtil.hexDump(buf.readSlice(6))); + position.set("homePlmn", ByteBufUtil.hexDump(buf.readSlice(6))); + break; + case 0x66: + position.set("imsi", BufferUtil.readString(buf, length)); + break; + case 0x75: + position.set("extraEnableControl", buf.readUnsignedInt()); + break; + default: + break; + } + + buf.readerIndex(endIndex); + } + + return position; + } + } diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java index 7c6a1de08..126334767 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java @@ -14,6 +14,9 @@ public class Minifinder2ProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, false, binary( "ab105a0512e19404011001383632333131303632373037333735093743c3ec640000000009374dc3ec6400000000093750c3ec6400000080092455c3ec640203935e0f22a318d6c7baacd6a2546751467bd009246ac3ec640203b35e0f22a318d6c7baacd6a2546751467bd009246cc3ec640203b35e0f22a318d6c7baacd6a2546751467bd009247ec3ec640203b35e0f22a318d6c7baacd6a2546751467bd0092492c3ec640203b35e0f22a318d6c7baacd6a2546751467bd00924a6c3ec640203b35e0f22a318d6c7baacd6a2546751467bd00924bac3ec640203b35e0f22a318d6c7baacd6a2546751467bd00924d2c3ec640203b35e0f22a7083a2f201a83a3f8084f84ae560924e7c3ec640203b35e0f22a7083a2f201a83a3f8084f84ae560924fbc3ec640203b35e0f22a7083a2f201a83a3f8084f84ae5609240fc4ec640203b35e0f22a7083a2f201a83a3f8084f84ae56092423c4ec640203b35d0f22a7083a2f201a83a3f8084f84ae56092437c4ec640203cb5d0f22a7083a2f201a83a3f8084f84ae5609244fc4ec640003cb5d092464c4ec640003cb5d092478c4ec640003cb5d09248cc4ec640003cb5d0924a0c4ec640003cb5d0924b4c4ec640003cb5d0924ccc4ec640003cb5d0924e5c4ec640003cb5d0924fec4ec6400037b5d092413c5ec6400037b5d092427c5ec6400017b5d0924b785ed640003cb530924d085ed640003ab530924e985ed640003ab530924fe85ed640003ab5309241286ed640003ab5309242686ed640003ab5309243a86ed640003ab5309244e86ed640003ab5309246786ed640003ab5309248086ed640003ab5309249986ed6400037b530924b286ed6400037b530924c686ed6400037b530924da86ed6400037b530924ee86ed6400037b5309240287ed6400037b5309241687ed6400037b5309242f87ed6400037b5309244787ed640003835309246187ed640003835309247a87ed640003835309249287ed64000383530924ab87ed64000383530924c487ed64000383530924d987ed64000383530924ed87ed640003835309240188ed640003835309241588ed640003835309242988ed640003d35309243a88ed640003d3530d02000000803788ed640000000009374188ed640400000009244188ed640003d35309244288ed640003d35309374b88ed640500000009244b88ed640003d35309375588ed640500000009245588ed640003d35309245788ed640003d35309375f88ed640700000009245f88ed640003d35309376988ed640800000009246988ed640003d35309246b88ed640203d3530f22a502184a2cfba0a42c768af4ab5009247188ed640203d3530f22a502184a2cfba0a42c768af4ab5009377388ed640a00000009247688ed640203d3530f22a502184a2cfba0a42c768af4ab5009247b88ed640203d3530f22a502184a2cfba0a42c768af4ab5009377d88ed640300000009247e88ed640203d3530f22a502184a2cfba0a42c768af4ab5009248088ed640203d3530f22a502184a2cfba0a42c768af4ab5009248588ed640203d3530f22a502184a2cfba0a42c768af4ab5009378788ed640000000009248a88ed640203d3530f22a502184a2cfba0a42c768af4ab5009248f88ed640203d3530f22a502184a2cfba0a42c768af4ab5009379188ed640000000009379288ed640000008009249288ed640203d3530f22a502184a2cfba0a42c768af4ab5009249488ed640203d3530f22a502184a2cfba0a42c768af4ab5009249988ed640203d3530f22a502184a2cfba0a42c768af4ab5009249e88ed640203d3530f22a502184a2cfba0a42c768af4ab500924a388ed640203d3530f22a502184a2cfba0a42c768af4ab500924a688ed640203d3530f22a502184a2cfba0a42c768af4ab50")); + verifyAttributes(decoder, binary( + "ab00cc029c9b0000020501040518200502cf290001100338363233313130363534393538393515043839343632303338303735303031383830343034070539eed3f9cec705064f93a7650507010b00002908cf2900010020050000d0000068915b00ae0000004f637420313920323032330031303a35393a3332261b53494d37353030457c4231315630325f3231303330337c50312e30325f3230323231313034050900000000050a00000003070b000000001e01070b010000001e01070b020000001e01070b030000001e01060c0000000000050d6e600580020e04050f0708008002100002110f02126406134d46303758041404a20e08160000000000000008160100000000000008160200000000000008160300000000000008160400000000000008160500000000000008160600000000000008160700000000000008160800000000000008160900000000000020177777772e676f6f676c652e636f6d2f6d6170733f713d252e37662c252e3766211868747470733a2f2f6c6f632e6d696e6966696e6465722e636f6d2f25732f25730519000001fe101a4d4630372e343631302e3233303300021c640a1d802acee6212966cf0803207b3e03217b040230000230010230020230030230040230050230060230070230080230090231000532580214010533820000000e406d326d2e74656c65322e636f6d014101421c4380431468756e7465726465762e6d696e6966696e6465722e636f6d0d440e01008005000000100e0000054505002c01014705500f1400f00d511002e803b84d7f0d0246f6430d511100f40100000000000000000d511200f40100000000000000000d511300f401000000000000000005527800030005532c0100000354500005551e002d400256050b57201c00002c010000ed61025d01055c890a0000057000000000037100001472000000000000000000000000000000000000000568f0000100057500000000074de36000000000")); + verifyAttribute(decoder, binary( "ab101c00d6f61e000110013836333932313033393939363038300937efd201640c000000"), "barkCount", 12L); -- cgit v1.2.3 From b7bd2ce8416a4b7bbc8a5e5171f0891d894e6bc7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 3 Feb 2024 08:29:43 -0800 Subject: Implement FleetGuide acknowledgement --- .../protocol/FleetGuideProtocolDecoder.java | 68 ++++++++++++++++++++-- .../protocol/FleetGuideProtocolDecoderTest.java | 3 + 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java index 9fddec922..ba4d9cfae 100644 --- a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -19,8 +19,10 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; import org.traccar.session.DeviceSession; @@ -38,9 +40,13 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - public static final int MSG_DATA = 0x10; - public static final int MSG_HEARTBEAT = 0x1A; - public static final int MSG_RESPONSE = 0x1C; + public static final int MSG_EMPTY = 0; + public static final int MSG_SYNC_REQ = 1; + public static final int MSG_SYNC_ACK = 2; + public static final int MSG_DATA_R_ACK = 3; + public static final int MSG_DATA_N_ACK = 4; + public static final int MSG_REP_R_ACK = 5; + public static final int MSG_REP_N_ACK = 6; @Override protected Object decode( @@ -53,9 +59,12 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { int length = BitUtil.to(options, 11); DeviceSession deviceSession; + Long deviceId; if (BitUtil.check(options, 11)) { - deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedIntLE())); + deviceId = buf.readUnsignedIntLE(); + deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); } else { + deviceId = null; deviceSession = getDeviceSession(channel, remoteAddress); } if (deviceSession == null) { @@ -63,12 +72,24 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { } int type; + Integer index; if (BitUtil.check(options, 12)) { - type = BitUtil.to(buf.readUnsignedByte(), 4); + int value = buf.readUnsignedByte(); + type = BitUtil.to(value, 4); + index = BitUtil.from(value, 4); } else { type = 0; + index = null; } + Integer responseType; + if (type == MSG_SYNC_REQ) { + responseType = MSG_SYNC_ACK; + } else { + responseType = null; + } + sendResponse(channel, remoteAddress, deviceId, responseType, index); + if (BitUtil.check(options, 13)) { buf.readUnsignedShortLE(); // acknowledgement } @@ -153,6 +174,43 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { return position; } + + private void sendResponse( + Channel channel, SocketAddress remoteAddress, Long deviceId, Integer type, Integer index) { + if (channel != null) { + + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x53); // signature + + int options = 0; + if (deviceId != null) { + options |= 1 << 11; + } + if (type != null) { + options |= 1 << 12; + } + if (index != null) { + options |= 1 << 13; + } + response.writeShortLE(options); + + if (deviceId != null) { + response.writeIntLE(deviceId.intValue()); + } + if (type != null) { + response.writeByte(type); + } + if (index != null) { + int mask = (1 << (index + 1)) - 1; + response.writeShortLE(mask); + } + response.writeShortLE(Checksum.crc16( + Checksum.CRC16_CCITT_FALSE, response.nioBuffer(1, response.writerIndex() - 1))); + + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + private int readVarSize(ByteBuf buf) { int b; int y = 0; diff --git a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java index 34b15d14b..363f33c5b 100644 --- a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class FleetGuideProtocolDecoderTest extends ProtocolTest { var decoder = inject(new FleetGuideProtocolDecoder(null)); + verifyNull(decoder, binary( + "5300188f8a020001f36a")); + verifyPositions(decoder, binary( "539e598f8a020003020700e378351ac39f040c04ffa92e806a28a13b1f00b638030c000067052c06ffffffff033006808001180003200100000700e478351ac40204303dab2e80cb27a13b1c00ac40021b30e778351ac502043082a72e8054020530bf30021b30e978351ac69f0d0c0433a72e80c123a13b2000df3807002579351ac79f06020a170000df28021b476179351ac8020f30021c81279d79351ac9020f30021c8207d979351aca020f30021c8157157a351acb022b8140517a351acc022b608d7a351acd022b60c97a351ace022b30057b351acf022b30417b351ad0022b307d7b351ad1020f3048021b30b97b351ad2020f3070030c004066021630f57b351ad30213841080021730317c351ad4021330c00217306d7c351ad5020f3050021b30a97c351ad602138170021830e57c351ad7020f3058021b30217d351ad8021385500218305d7d351ad9022b8110997d351ada022b8170d57d351adb022b30117e351adc020f3068030ce184680216304d7e351add020f3060030ce34469021630897e351ade021260e4021830c57e351adf021230e5021830017f351ae002293022f2")); -- cgit v1.2.3 From 444d54e792418333b98a109490b7eaffc96cdf53 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 4 Feb 2024 09:47:19 -0800 Subject: Change to if statement --- src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java index 3a0962584..aabc24887 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java @@ -29,7 +29,7 @@ public class TeltonikaFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - while (buf.isReadable() && buf.getByte(buf.readerIndex()) == (byte) 0xff) { + if (buf.isReadable() && buf.getByte(buf.readerIndex()) == (byte) 0xff) { return buf.readRetainedSlice(1); } -- cgit v1.2.3 From c506f723c905fed6995cde26168dce9948599fd4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 5 Feb 2024 21:42:08 -0800 Subject: Add unique id validation --- src/main/java/org/traccar/model/Device.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index e07815976..a3088a613 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -53,6 +53,9 @@ public class Device extends GroupedModel implements Disableable, Schedulable { } public void setUniqueId(String uniqueId) { + if (uniqueId.contains("../") || uniqueId.contains("..\\")) { + throw new IllegalArgumentException("Invalid unique id"); + } this.uniqueId = uniqueId.trim(); } -- cgit v1.2.3 From 9ca9c0c146125eaa9a6a3e875e5dd596b6fa228b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 7 Feb 2024 20:58:19 -0800 Subject: Reverse Teltonika driver id --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 537990265..2f0874797 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -231,7 +231,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(74, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 3, b.readInt() * 0.1)); register(75, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 4, b.readInt() * 0.1)); register(78, null, (p, b) -> { - long driverUniqueId = b.readLong(); + long driverUniqueId = b.readLongLE(); if (driverUniqueId > 0) { p.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); } -- cgit v1.2.3 From 3f55f474fde34c8110b48cb1ac472671ca5f80fc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 8 Feb 2024 06:59:14 -0800 Subject: Handle last FleetGuide position --- .../protocol/FleetGuideProtocolDecoder.java | 34 +++++++++++++--------- .../protocol/FleetGuideProtocolDecoderTest.java | 3 ++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java index ba4d9cfae..b4593d843 100644 --- a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -82,13 +82,15 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { index = null; } - Integer responseType; - if (type == MSG_SYNC_REQ) { - responseType = MSG_SYNC_ACK; - } else { - responseType = null; + if (type != MSG_DATA_N_ACK && type != MSG_REP_N_ACK) { + Integer responseType; + if (type == MSG_SYNC_REQ) { + responseType = MSG_SYNC_ACK; + } else { + responseType = null; + } + sendResponse(channel, remoteAddress, deviceId, responseType, index); } - sendResponse(channel, remoteAddress, deviceId, responseType, index); if (BitUtil.check(options, 13)) { buf.readUnsignedShortLE(); // acknowledgement @@ -116,7 +118,7 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { int recordEndIndex = data.readerIndex() + recordLength; if (recordTypes.contains(recordType)) { - positions.add(processPosition(position)); + processPosition(positions, position); position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); recordTypes.clear(); @@ -159,19 +161,23 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { } + processPosition(positions, position); + data.release(); return positions.isEmpty() ? null : positions; } - private Position processPosition(Position position) { - if (position.getFixTime() == null) { - position.setTime(new Date()); - } - if (!position.getAttributes().containsKey(Position.KEY_SATELLITES)) { - getLastLocation(position, null); + private void processPosition(List positions, Position position) { + if (!position.getAttributes().isEmpty()) { + if (position.getFixTime() == null) { + position.setTime(new Date()); + } + if (!position.getAttributes().containsKey(Position.KEY_SATELLITES)) { + getLastLocation(position, null); + } + positions.add(position); } - return position; } diff --git a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java index 363f33c5b..8146f6a3e 100644 --- a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class FleetGuideProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "5300188f8a020001f36a")); + verifyNull(decoder, binary( + "5322188f8a0200140700f355831a83ec06030c008065052c06ffffffff033006808001180003200100005ec0")); + verifyPositions(decoder, binary( "539e598f8a020003020700e378351ac39f040c04ffa92e806a28a13b1f00b638030c000067052c06ffffffff033006808001180003200100000700e478351ac40204303dab2e80cb27a13b1c00ac40021b30e778351ac502043082a72e8054020530bf30021b30e978351ac69f0d0c0433a72e80c123a13b2000df3807002579351ac79f06020a170000df28021b476179351ac8020f30021c81279d79351ac9020f30021c8207d979351aca020f30021c8157157a351acb022b8140517a351acc022b608d7a351acd022b60c97a351ace022b30057b351acf022b30417b351ad0022b307d7b351ad1020f3048021b30b97b351ad2020f3070030c004066021630f57b351ad30213841080021730317c351ad4021330c00217306d7c351ad5020f3050021b30a97c351ad602138170021830e57c351ad7020f3058021b30217d351ad8021385500218305d7d351ad9022b8110997d351ada022b8170d57d351adb022b30117e351adc020f3068030ce184680216304d7e351add020f3060030ce34469021630897e351ade021260e4021830c57e351adf021230e5021830017f351ae002293022f2")); -- cgit v1.2.3 From fe771851995da97ffa2fb50e21bd437bca208eac Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 8 Feb 2024 07:26:52 -0800 Subject: Support RST command responses --- src/main/java/org/traccar/protocol/RstProtocolDecoder.java | 13 ++++++++++++- .../java/org/traccar/protocol/RstProtocolDecoderTest.java | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java index 2493f0d9f..eafa4d3d7 100644 --- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2024 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. @@ -143,6 +143,17 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { return position; + } else if (type == 134) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_RESULT, String.valueOf(type)); + + return position; + } else { return null; diff --git a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java index fc932fe9e..a750d0311 100644 --- a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class RstProtocolDecoderTest extends ProtocolTest { var decoder = inject(new RstProtocolDecoder(null)); + verifyAttribute(decoder, text( + "RST;A;RST-MINI-4Gv3;V9.10;009521405;1;134;FIM;"), + Position.KEY_RESULT, "134"); + verifyAttribute(decoder, text( "RST;A;RST-MINIv5;V9.08;009767055;248;55;14-12-2023 19:34:20;14-12-2023 19:34:21;-12.923640;-38.388313;0;14;17;1;4;15;00;B0;00;1A;02;12.18;4.02;65;21;FE;0000;01;C0;001606017031;0002;FIM;"), Position.KEY_DRIVER_UNIQUE_ID, "001606017031"); -- cgit v1.2.3 From 0c8b5c1ab1f83cc0fc6d2f17cdf808388b383e14 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 8 Feb 2024 17:49:28 -0800 Subject: Handle no remote address --- .../java/org/traccar/session/ConnectionManager.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 1461c66ea..121b876c5 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -188,17 +188,19 @@ public class ConnectionManager implements BroadcastInterface { public void deviceDisconnected(Channel channel, boolean supportsOffline) { SocketAddress remoteAddress = channel.remoteAddress(); - Map endpointSessions = sessionsByEndpoint.remove(remoteAddress); - if (endpointSessions != null) { - for (DeviceSession deviceSession : endpointSessions.values()) { - if (supportsOffline) { - updateDevice(deviceSession.getDeviceId(), Device.STATUS_OFFLINE, null); + if (remoteAddress != null) { + Map endpointSessions = sessionsByEndpoint.remove(remoteAddress); + if (endpointSessions != null) { + for (DeviceSession deviceSession : endpointSessions.values()) { + if (supportsOffline) { + updateDevice(deviceSession.getDeviceId(), Device.STATUS_OFFLINE, null); + } + sessionsByDeviceId.remove(deviceSession.getDeviceId()); + cacheManager.removeDevice(deviceSession.getDeviceId()); } - sessionsByDeviceId.remove(deviceSession.getDeviceId()); - cacheManager.removeDevice(deviceSession.getDeviceId()); } + unknownByEndpoint.remove(remoteAddress); } - unknownByEndpoint.remove(remoteAddress); } public void deviceUnknown(long deviceId) { -- cgit v1.2.3 From f632b15098776b35910834aabc35bb62737c6d78 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Feb 2024 07:13:09 -0800 Subject: Handle MT600 no location messages --- .../org/traccar/protocol/Tlt2hProtocolDecoder.java | 31 +++++++++++++++------- .../traccar/protocol/Tlt2hProtocolDecoderTest.java | 10 ++++++- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index 79488acc0..4b11cbc74 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2024 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. @@ -63,8 +63,9 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { .number("(x+)") // cell id .groupEnd("?") .text("$GPRMC,") - .number("(dd)(dd)(dd).d+,") // time (hhmmss.sss) + .number("(?:(dd)(dd)(dd).d+)?,") // time (hhmmss.sss) .expression("([AVL]),") // validity + .groupBegin() .number("(d+)(dd.d+),") // latitude .expression("([NS]),") .number("(d+)(dd.d+),") // longitude @@ -72,6 +73,7 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { .number("(d+.?d*)?,") // speed .number("(d+.?d*)?,") // course .number("(dd)(dd)(dd)") // date (ddmmyy) + .groupEnd("?") .any() .compile(); @@ -190,17 +192,26 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(network); } - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + DateBuilder dateBuilder = new DateBuilder(); + if (parser.hasNext(3)) { + dateBuilder.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + } position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); + if (parser.hasNext()) { + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + } else { + getLastLocation(position, null); + } } else { continue; diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java index a64a10450..8a7ba84ab 100644 --- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java @@ -11,6 +11,14 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tlt2hProtocolDecoder(null)); + verifyPositions(decoder, false, text( + "#868105044690301#MT600+#0000#0#0#129#40#0#AUTOLOW#1\r\n" + + "#072030fa20c$GPRMC,,V,,,,,,,,,,A*5C\r\n")); + + verifyPositions(decoder, text( + "#868105044690301#MT600+#0000#0#0#143#40#0#AUTO#1\r\n", + "#072030fcf21$GPRMC,155616.00,A,4931.9210,N,09652.5290,W,53.80,90.00,150224,,,A*48\r\n")); + verifyAttribute(decoder, text( "#867665041689485#MT700N#0000#HT#1\r\n", "#5065$GPRMC,148996.00,A,2485.2458,N,01258.4535,E,,,151348,,,A*5D\r\n"), @@ -24,7 +32,7 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest { "#862255061825896#MT710#0000#TOWED#1\r\n", "#39#$WIFI,015259.00,A,-47,7483C2DBC0B0,-48,7683C2ABC0B0,-48,7683C29BC0B0,-48,7683C2CBC0B0,-48,7683C2BBC0B0,151123*74\r\n")); - verifyNull(decoder, text( + verifyPositions(decoder, false, text( "#860517049471362#MT700#0000#AUTO#1\r\n", "#36$GPRMC,,V,,,,,,,,,,A*5C\r\n")); -- cgit v1.2.3 From a8ab00a53f8015df041ced9ba012294cea1068e5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Feb 2024 07:46:36 -0800 Subject: Finish FleetGuide implementation --- .../protocol/FleetGuideProtocolDecoder.java | 79 ++++++++++++++++++++-- .../protocol/FleetGuideProtocolDecoderTest.java | 11 ++- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java index b4593d843..8f679525b 100644 --- a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -29,10 +29,8 @@ import org.traccar.session.DeviceSession; import java.net.SocketAddress; import java.util.Date; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Set; public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { @@ -108,8 +106,6 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - Set recordTypes = new HashSet<>(); - while (data.isReadable()) { int recordHeader = data.readUnsignedShortLE(); @@ -117,13 +113,11 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { int recordType = BitUtil.from(recordHeader, 10); int recordEndIndex = data.readerIndex() + recordLength; - if (recordTypes.contains(recordType)) { + if (recordType == 0 && position.getDeviceTime() != null) { processPosition(positions, position); position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - recordTypes.clear(); } - recordTypes.add(recordType); switch (recordType) { case 0: @@ -153,6 +147,77 @@ public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { position.setAltitude(-position.getAltitude()); } break; + case 3: + int powerLow = data.readUnsignedByte(); + int powerFlags = data.readUnsignedByte(); + int batteryHigh = data.readUnsignedByte(); + position.set(Position.KEY_POWER, (powerLow + (BitUtil.to(powerFlags, 5) << 8)) * 0.01); + position.set(Position.KEY_IGNITION, BitUtil.check(powerFlags, 5)); + position.set(Position.KEY_BATTERY, (BitUtil.from(powerFlags, 6) + (batteryHigh << 2)) * 0.01); + if (recordLength >= 4) { + int extraFlags = data.readUnsignedByte(); + if (BitUtil.check(extraFlags, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + } + if (BitUtil.check(extraFlags, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + } + } + break; + case 6: + position.set(Position.KEY_INPUT, data.readUnsignedByte()); + break; + case 7: + position.set(Position.KEY_OUTPUT, data.readUnsignedByte()); + break; + case 8: + int adcMask = data.readUnsignedByte(); + for (int i = 0; i < 8; i++) { + if (BitUtil.check(adcMask, i)) { + position.set(Position.PREFIX_ADC + (i + 1), data.readUnsignedShortLE()); + } + } + break; + case 11: + int fuelMask = data.readUnsignedByte(); + for (int i = 1; i < 8; i++) { + if (BitUtil.check(fuelMask, i)) { + position.set("fuel" + i, data.readUnsignedShortLE()); + } + } + break; + case 12: + int fuelTempMask = data.readUnsignedByte(); + for (int i = 1; i < 8; i++) { + if (BitUtil.check(fuelTempMask, i)) { + position.set("fuelTemp" + i, (int) data.readByte()); + } + } + break; + case 13: + int tempMask = data.readUnsignedByte(); + for (int i = 0; i < 8; i++) { + if (BitUtil.check(tempMask, i)) { + position.set(Position.PREFIX_TEMP + (i + 1), data.readShortLE() * 0.01); + } + } + break; + case 18: + int sensorIndex = data.readUnsignedByte(); + switch (recordLength - 1) { + case 1: + position.set("sensor" + sensorIndex, data.readUnsignedByte()); + break; + case 2: + position.set("sensor" + sensorIndex, data.readUnsignedShortLE()); + break; + case 4: + position.set("sensor" + sensorIndex, data.readUnsignedIntLE()); + break; + default: + break; + } + break; default: break; } diff --git a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java index 8146f6a3e..3cd74766d 100644 --- a/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FleetGuideProtocolDecoderTest.java @@ -13,12 +13,21 @@ public class FleetGuideProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "5300188f8a020001f36a")); - verifyNull(decoder, binary( + verifyPositions(decoder, false, binary( "5322188f8a0200140700f355831a83ec06030c008065052c06ffffffff033006808001180003200100005ec0")); verifyPositions(decoder, binary( "539e598f8a020003020700e378351ac39f040c04ffa92e806a28a13b1f00b638030c000067052c06ffffffff033006808001180003200100000700e478351ac40204303dab2e80cb27a13b1c00ac40021b30e778351ac502043082a72e8054020530bf30021b30e978351ac69f0d0c0433a72e80c123a13b2000df3807002579351ac79f06020a170000df28021b476179351ac8020f30021c81279d79351ac9020f30021c8207d979351aca020f30021c8157157a351acb022b8140517a351acc022b608d7a351acd022b60c97a351ace022b30057b351acf022b30417b351ad0022b307d7b351ad1020f3048021b30b97b351ad2020f3070030c004066021630f57b351ad30213841080021730317c351ad4021330c00217306d7c351ad5020f3050021b30a97c351ad602138170021830e57c351ad7020f3058021b30217d351ad8021385500218305d7d351ad9022b8110997d351ada022b8170d57d351adb022b30117e351adc020f3068030ce184680216304d7e351add020f3060030ce34469021630897e351ade021260e4021830c57e351adf021230e5021830017f351ae002293022f2")); + verifyPositions(decoder, binary( + "538958235a02008408070027398f1a7da3040c0485c7437f9db8a635ca016189030c76a567052c06bd05ffff033006138009340f69fb0080008000800118010320018005070029398f1a7e08043b39f0437f14b9a635cb010288030c7108233b2b398f1a7f08043bec18447f7fbca6357c010b8008263b2d398f1a8008043be53d447f61c0a63562011480030c7708213b6f3b")); + + verifyPositions(decoder, binary( + "53361886b60e00540700cf3b8f1a838d060e041dc683a1b672a04b0000ba885d00030c0ea567052c06ffffffff03300680800118000720070000000000006bc3")); + + verifyPositions(decoder, binary( + "53dd581fc10e0094080700373d8f1a5e2f090e04cbb6c2a3d3078f4b5d023090b500030cac6567052c06ffffffff0330068080054810fdfdfdff0548121bf0000005481321d4830005481454cf08040e15eee20100054816770308040e171c0208040718281f0804071984000804071a583a000001180107200781050000000007003b3d8f1a5f2f040e04dcfbc2a3b15a8f4b67023890b4081c7c1f08067c2e08067c61081b7c842008057c8308067c443c08107c3e3d8f1a6008047cf125c3a31ca48f4b7c0242081e7c2208067c3908067c6b08067cef08147cac21080c7ce03e080e7cbb62")); + } } -- cgit v1.2.3 From 5a5a0e43d3b123780775f723c1c35a417a4e8265 Mon Sep 17 00:00:00 2001 From: meysamrt <46737899+MeysamRT76@users.noreply.github.com> Date: Sun, 18 Feb 2024 16:44:28 +0330 Subject: Refactor: Remove duplicated code in get function (ServerResource.java) Eliminate duplicated code in get function to enhance maintainability and readability. --- src/main/java/org/traccar/api/resource/ServerResource.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 66ecc74e1..76c8e14c7 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -93,15 +93,10 @@ public class ServerResource extends BaseResource { server.setOpenIdEnabled(openIdProvider != null); server.setOpenIdForce(openIdProvider != null && openIdProvider.getForce()); User user = permissionsService.getUser(getUserId()); - if (user != null) { - if (user.getAdministrator()) { - server.setStorageSpace(Log.getStorageSpace()); - } - } else { - server.setNewServer(UserUtil.isEmpty(storage)); - } if (user != null && user.getAdministrator()) { server.setStorageSpace(Log.getStorageSpace()); + } else { + server.setNewServer(UserUtil.isEmpty(storage)); } return server; } -- cgit v1.2.3 From 51d6275a3cb5ed50c34dd2b0ca1252860793244a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 18 Feb 2024 15:20:30 -0800 Subject: Support Amber IoT asset tracker --- .../traccar/protocol/SigfoxProtocolDecoder.java | 27 +++++++++++++++++----- .../protocol/SigfoxProtocolDecoderTest.java | 9 ++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index 6f739a1a4..9380d2327 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2024 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. @@ -23,6 +23,7 @@ import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import org.traccar.BaseHttpProtocolDecoder; import org.traccar.helper.BufferUtil; +import org.traccar.model.Device; import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; @@ -154,20 +155,34 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { } else if (jsonContains(json, "data")) { + String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(json.getString("data"))); try { - int event = buf.readUnsignedByte(); - if (event == 0x0f || event == 0x1f) { + int header = buf.readUnsignedByte(); + if ("Amber".equals(model)) { + + int flags = buf.readUnsignedByte(); + position.set(Position.KEY_MOTION, BitUtil.check(flags, 1)); + + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.02); + position.set(Position.PREFIX_TEMP + 1, (int) buf.readByte()); + + position.setValid(true); + position.setLatitude(buf.readInt() / 60000.0); + position.setLongitude(buf.readInt() / 60000.0); + + } else if (header == 0x0f || header == 0x1f) { - position.setValid(event >> 4 > 0); + position.setValid(header >> 4 > 0); position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001); position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001); position.set(Position.KEY_BATTERY, (int) buf.readUnsignedByte()); - } else if (event >> 4 <= 3 && buf.writerIndex() == 12) { + } else if (header >> 4 <= 3 && buf.writerIndex() == 12) { - if (BitUtil.to(event, 4) == 0) { + if (BitUtil.to(header, 4) == 0) { position.setValid(true); position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java index cc6c17014..8a275ce9a 100644 --- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java @@ -3,8 +3,11 @@ package org.traccar.protocol; import io.netty.handler.codec.http.HttpMethod; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Device; import org.traccar.model.Position; +import static org.mockito.Mockito.when; + public class SigfoxProtocolDecoderTest extends ProtocolTest { @Test @@ -43,6 +46,12 @@ public class SigfoxProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, request(HttpMethod.POST, "/", buffer("%7B++%22device%22%3A%222BF839%22%2C++%22time%22%3A1510605882%2C++%22duplicate%22%3Afalse%2C++%22snr%22%3A45.61%2C++%22station%22%3A%2235A9%22%2C++%22data%22%3A%2200bd6475e907398e562d01b9%22%2C++%22avgSnr%22%3A45.16%2C++%22lat%22%3A-38.0%2C++%22lng%22%3A145.0%2C++%22rssi%22%3A-98.00%2C++%22seqNumber%22%3A228+%7D="))); + var device = decoder.getCacheManager().getObject(Device.class, 1); + when(device.getModel()).thenReturn("Amber"); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{ \"deviceId\":\"284019F\", \"timestamp\":\"1707375610\", \"seqNo\":\"42\", \"data\":\"0100b019ffe8645d0019e513\", \"linkQuality\":\"Excellent\", \"operator\":\"SIGFOX_South_Africa_Sqwidnet\", \"country\":\"710\" }"))); + } } -- cgit v1.2.3 From 15a478a959ea6ff4000c6b14d54edc9d2c37e06d Mon Sep 17 00:00:00 2001 From: meysamrt <46737899+MeysamRT76@users.noreply.github.com> Date: Mon, 19 Feb 2024 08:54:26 +0330 Subject: Update ServerResource.java --- src/main/java/org/traccar/api/resource/ServerResource.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 76c8e14c7..2a72d2773 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -93,8 +93,10 @@ public class ServerResource extends BaseResource { server.setOpenIdEnabled(openIdProvider != null); server.setOpenIdForce(openIdProvider != null && openIdProvider.getForce()); User user = permissionsService.getUser(getUserId()); - if (user != null && user.getAdministrator()) { - server.setStorageSpace(Log.getStorageSpace()); + if (user != null) { + if (user.getAdministrator()) { + server.setStorageSpace(Log.getStorageSpace()); + } } else { server.setNewServer(UserUtil.isEmpty(storage)); } -- cgit v1.2.3 From efd9e261791942334dbf4a911883a1b2b791f282 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 19 Feb 2024 11:53:08 -0800 Subject: Streamline model name access --- src/main/java/org/traccar/BaseProtocolDecoder.java | 10 ++++++++++ src/main/java/org/traccar/BaseProtocolEncoder.java | 11 +++++++++++ .../java/org/traccar/protocol/DualcamProtocolDecoder.java | 3 +-- src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java | 7 +++---- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 3 +-- .../java/org/traccar/protocol/MeiligaoProtocolEncoder.java | 3 +-- .../java/org/traccar/protocol/MeitrackProtocolDecoder.java | 8 ++------ .../java/org/traccar/protocol/Minifinder2ProtocolEncoder.java | 4 +--- src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java | 5 +---- .../java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 4 +--- src/main/java/org/traccar/session/ConnectionManager.java | 2 +- src/main/java/org/traccar/session/DeviceSession.java | 9 ++++++++- src/test/java/org/traccar/BaseTest.java | 3 ++- .../org/traccar/protocol/Minifinder2ProtocolEncoderTest.java | 3 +-- .../java/org/traccar/protocol/SigfoxProtocolDecoderTest.java | 3 +-- 15 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 4d4086c3c..495a866c0 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -51,6 +51,8 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { private MediaManager mediaManager; private CommandsManager commandsManager; + private String modelOverride; + public BaseProtocolDecoder(Protocol protocol) { this.protocol = protocol; } @@ -141,6 +143,14 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { } } + public void setModelOverride(String modelOverride) { + this.modelOverride = modelOverride; + } + + public String getDeviceModel(DeviceSession deviceSession) { + return modelOverride != null ? modelOverride : deviceSession.getModel(); + } + public void getLastLocation(Position position, Date deviceTime) { if (position.getDeviceId() != 0) { position.setOutdated(true); diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java index b9ca16838..e357c27dc 100644 --- a/src/main/java/org/traccar/BaseProtocolEncoder.java +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -39,6 +39,8 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter private CacheManager cacheManager; + private String modelOverride; + public BaseProtocolEncoder(Protocol protocol) { this.protocol = protocol; } @@ -68,6 +70,15 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter } } + public void setModelOverride(String modelOverride) { + this.modelOverride = modelOverride; + } + + public String getDeviceModel(long deviceId) { + String model = getCacheManager().getObject(Device.class, deviceId).getModel(); + return modelOverride != null ? modelOverride : model; + } + @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index 75cd52384..411e2b9d7 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -19,7 +19,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.model.Device; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -77,7 +76,7 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); long settings = buf.readUnsignedInt(); if (channel != null && deviceSession != null) { - model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); + model = getDeviceModel(deviceSession); ByteBuf response = Unpooled.buffer(); if (BitUtil.check(settings, 25)) { response.writeShort(MSG_PATH_REQUEST); diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java index dc5dd446f..fd6bb8451 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java @@ -23,7 +23,6 @@ import org.traccar.config.Keys; import org.traccar.helper.Checksum; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; -import org.traccar.model.Device; import java.nio.charset.StandardCharsets; @@ -74,11 +73,11 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder { String password = AttributeUtil.getDevicePassword( getCacheManager(), command.getDeviceId(), getProtocolName(), "123456"); - Device device = getCacheManager().getObject(Device.class, command.getDeviceId()); + String model = getDeviceModel(command.getDeviceId()); switch (command.getType()) { case Command.TYPE_ENGINE_STOP: - if ("G109".equals(device.getModel())) { + if ("G109".equals(model)) { return encodeContent(command.getDeviceId(), "DYD#"); } else if (alternative) { return encodeContent(command.getDeviceId(), "DYD," + password + "#"); @@ -86,7 +85,7 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder { return encodeContent(command.getDeviceId(), "Relay,1#"); } case Command.TYPE_ENGINE_RESUME: - if ("G109".equals(device.getModel())) { + if ("G109".equals(model)) { return encodeContent(command.getDeviceId(), "HFYD#"); } else if (alternative) { return encodeContent(command.getDeviceId(), "HFYD," + password + "#"); diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 5745909c7..343d42e09 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -28,7 +28,6 @@ import org.traccar.helper.PatternBuilder; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; -import org.traccar.model.Device; import org.traccar.helper.BitUtil; import java.net.SocketAddress; @@ -226,7 +225,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return null; } - String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); + String model = getDeviceModel(deviceSession); Position position = new Position(getProtocolName()); diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java index 5859d91ce..6d3b4f7e9 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java @@ -24,7 +24,6 @@ import org.traccar.helper.Checksum; import org.traccar.helper.DataConverter; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; -import org.traccar.model.Device; import java.nio.charset.StandardCharsets; import java.util.Set; @@ -64,7 +63,7 @@ public class MeiligaoProtocolEncoder extends BaseProtocolEncoder { int outputCount; int outputType; - String model = getCacheManager().getObject(Device.class, deviceId).getModel(); + String model = getDeviceModel(deviceId); if (model != null && Set.of("TK510", "GT08", "TK208", "TK228", "MT05").contains(model)) { outputCount = 5; diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 965c8ee0d..88b6380a5 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -20,7 +20,6 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.model.Device; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -38,6 +37,7 @@ import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; public class MeitrackProtocolDecoder extends BaseProtocolDecoder { @@ -206,11 +206,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + i, parser.nextHexInt()); } - String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); - if (model == null) { - model = ""; - } - switch (model.toUpperCase()) { + switch (Objects.requireNonNullElse(getDeviceModel(deviceSession), "").toUpperCase()) { case "MVT340": case "MVT380": position.set(Position.KEY_BATTERY, parser.nextHexInt() * 3.0 * 2.0 / 1024.0); diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java index 72ac9db4e..6e330a4dd 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java @@ -21,7 +21,6 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.Protocol; import org.traccar.helper.Checksum; import org.traccar.model.Command; -import org.traccar.model.Device; import java.nio.charset.StandardCharsets; @@ -55,8 +54,7 @@ public class Minifinder2ProtocolEncoder extends BaseProtocolEncoder { content.writeByte(0xF0); // type } - Device device = getCacheManager().getObject(Device.class, command.getDeviceId()); - if ("Nano".equalsIgnoreCase(device.getModel())) { + if ("Nano".equalsIgnoreCase(getDeviceModel(command.getDeviceId()))) { ByteBuf content = Unpooled.buffer(); if (command.getType().equals(Command.TYPE_FIRMWARE_UPDATE)) { String url = command.getString(Command.KEY_DATA); diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index 9380d2327..e0dfab9b2 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -23,7 +23,6 @@ import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import org.traccar.BaseHttpProtocolDecoder; import org.traccar.helper.BufferUtil; -import org.traccar.model.Device; import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; @@ -155,12 +154,10 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { } else if (jsonContains(json, "data")) { - String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); - ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(json.getString("data"))); try { int header = buf.readUnsignedByte(); - if ("Amber".equals(model)) { + if ("Amber".equals(getDeviceModel(deviceSession))) { int flags = buf.readUnsignedByte(); position.set(Position.KEY_MOTION, BitUtil.check(flags, 1)); diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 2f0874797..6197c6c13 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -21,7 +21,6 @@ import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.helper.BufferUtil; -import org.traccar.model.Device; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -654,7 +653,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { if (deviceSession == null) { return null; } - String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); for (int i = 0; i < count; i++) { Position position = new Position(getProtocolName()); @@ -680,7 +678,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } else if (codec == CODEC_12) { decodeSerial(channel, remoteAddress, deviceSession, position, buf); } else { - decodeLocation(position, buf, codec, model); + decodeLocation(position, buf, codec, getDeviceModel(deviceSession)); } if (!position.getOutdated() || !position.getAttributes().isEmpty()) { diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 121b876c5..42dcf5ce9 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -147,7 +147,7 @@ public class ConnectionManager implements BroadcastInterface { } DeviceSession deviceSession = new DeviceSession( - device.getId(), device.getUniqueId(), protocol, channel, remoteAddress); + device.getId(), device.getUniqueId(), device.getModel(), protocol, channel, remoteAddress); endpointSessions.put(device.getUniqueId(), deviceSession); sessionsByEndpoint.put(remoteAddress, endpointSessions); sessionsByDeviceId.put(device.getId(), deviceSession); diff --git a/src/main/java/org/traccar/session/DeviceSession.java b/src/main/java/org/traccar/session/DeviceSession.java index 009f90f5a..f124ca7f9 100644 --- a/src/main/java/org/traccar/session/DeviceSession.java +++ b/src/main/java/org/traccar/session/DeviceSession.java @@ -29,14 +29,17 @@ public class DeviceSession { private final long deviceId; private final String uniqueId; + private final String model; private final Protocol protocol; private final Channel channel; private final SocketAddress remoteAddress; public DeviceSession( - long deviceId, String uniqueId, Protocol protocol, Channel channel, SocketAddress remoteAddress) { + long deviceId, String uniqueId, String model, + Protocol protocol, Channel channel, SocketAddress remoteAddress) { this.deviceId = deviceId; this.uniqueId = uniqueId; + this.model = model; this.protocol = protocol; this.channel = channel; this.remoteAddress = remoteAddress; @@ -50,6 +53,10 @@ public class DeviceSession { return uniqueId; } + public String getModel() { + return model; + } + public Channel getChannel() { return channel; } diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java index 2ace781f3..ce19d8ace 100644 --- a/src/test/java/org/traccar/BaseTest.java +++ b/src/test/java/org/traccar/BaseTest.java @@ -33,7 +33,8 @@ public class BaseTest { var connectionManager = mock(ConnectionManager.class); var uniqueIdsProvided = new HashSet(); when(connectionManager.getDeviceSession(any(), any(), any(), any(String[].class))).thenAnswer(invocation -> { - var mock = new DeviceSession(1L, "", mock(Protocol.class), mock(Channel.class), mock(SocketAddress.class)); + var mock = new DeviceSession( + 1L, "", null, mock(Protocol.class), mock(Channel.class), mock(SocketAddress.class)); if (uniqueIdsProvided.isEmpty()) { if (invocation.getArguments().length > 3) { uniqueIdsProvided.add(true); diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java index ef6ff6dd9..32c8a9ce6 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java @@ -14,8 +14,7 @@ public class Minifinder2ProtocolEncoderTest extends ProtocolTest { var encoder = inject(new Minifinder2ProtocolEncoder(null)); - var device = encoder.getCacheManager().getObject(Device.class, 1); - when(device.getModel()).thenReturn("Nano"); + encoder.setModelOverride("Nano"); Command command = new Command(); command.setDeviceId(1); diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java index 8a275ce9a..c7d0671c0 100644 --- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java @@ -46,8 +46,7 @@ public class SigfoxProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, request(HttpMethod.POST, "/", buffer("%7B++%22device%22%3A%222BF839%22%2C++%22time%22%3A1510605882%2C++%22duplicate%22%3Afalse%2C++%22snr%22%3A45.61%2C++%22station%22%3A%2235A9%22%2C++%22data%22%3A%2200bd6475e907398e562d01b9%22%2C++%22avgSnr%22%3A45.16%2C++%22lat%22%3A-38.0%2C++%22lng%22%3A145.0%2C++%22rssi%22%3A-98.00%2C++%22seqNumber%22%3A228+%7D="))); - var device = decoder.getCacheManager().getObject(Device.class, 1); - when(device.getModel()).thenReturn("Amber"); + decoder.setModelOverride("Amber"); verifyPosition(decoder, request(HttpMethod.POST, "/", buffer("{ \"deviceId\":\"284019F\", \"timestamp\":\"1707375610\", \"seqNo\":\"42\", \"data\":\"0100b019ffe8645d0019e513\", \"linkQuality\":\"Excellent\", \"operator\":\"SIGFOX_South_Africa_Sqwidnet\", \"country\":\"710\" }"))); -- cgit v1.2.3 From 8cf3fcd643faebd9cb0937bc1e8454a22ad8b137 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 19 Feb 2024 13:27:02 -0800 Subject: Support GV355CEU CAN data --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 36 ++++++++++++++++++---- .../protocol/Gl200TextProtocolDecoderTest.java | 5 +++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 0628a06d4..8fb30e2ad 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -16,6 +16,7 @@ package org.traccar.protocol; import io.netty.buffer.Unpooled; +import org.apache.commons.lang3.StringUtils; import org.traccar.BaseProtocolDecoder; import org.traccar.helper.DataConverter; import org.traccar.session.DeviceSession; @@ -419,17 +420,17 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); position.setDeviceId(deviceSession.getDeviceId()); - String deviceName = values[index++]; + String model = StringUtils.firstNonEmpty(values[index++], getDeviceModel(deviceSession)); index += 1; // report type - index += 1; // canbus state + index += 1; // can bus state long reportMask = Long.parseLong(values[index++], 16); long reportMaskExt = 0; if (BitUtil.check(reportMask, 0)) { position.set(Position.KEY_VIN, values[index++]); } - if (BitUtil.check(reportMask, 1)) { - position.set(Position.KEY_IGNITION, Integer.parseInt(values[index++]) > 0); + if (BitUtil.check(reportMask, 1) && !values[index++].isEmpty()) { + position.set(Position.KEY_IGNITION, Integer.parseInt(values[index - 1]) > 0); } if (BitUtil.check(reportMask, 2)) { position.set(Position.KEY_OBD_ODOMETER, values[index++]); @@ -491,7 +492,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) { position.set("engineOverspeed", Double.parseDouble(values[index - 1])); } - if ("GV350M".equals(deviceName)) { + if ("GV350M".equals(model)) { if (BitUtil.check(reportMask, 22)) { index += 1; // impulse distance } @@ -501,6 +502,28 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMask, 24)) { index += 1; // catalyst liquid level } + } else if ("GV355CEU".equals(model)) { + if (BitUtil.check(reportMask, 22)) { + index += 1; // impulse distance + } + if (BitUtil.check(reportMask, 23)) { + index += 1; // engine cold starts + } + if (BitUtil.check(reportMask, 24)) { + index += 1; // engine all starts + } + if (BitUtil.check(reportMask, 25)) { + index += 1; // engine starts by ignition + } + if (BitUtil.check(reportMask, 26)) { + index += 1; // total engine cold running time + } + if (BitUtil.check(reportMask, 27)) { + index += 1; // handbrake applies during ride + } + if (BitUtil.check(reportMask, 28)) { + index += 1; // electric report mask + } } if (BitUtil.check(reportMask, 29) && !values[index++].isEmpty()) { reportMaskExt = Long.parseLong(values[index - 1], 16); @@ -581,7 +604,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - if (BitUtil.check(reportMask, 30)) { + if (!"GV355CEU".equals(model) && BitUtil.check(reportMask, 30)) { while (values[index].isEmpty()) { index += 1; } @@ -606,6 +629,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { index += 1; // reserved } + index = values.length - 2; if (ignoreFixTime) { position.setTime(dateFormat.parse(values[index])); } else { diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 2c012eb6f..6327f6579 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -478,6 +478,11 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { verifyAttributes(decoder, buffer( "+ACK:GTGEO,1A0102,135790246811220,,0,0008,20100310172830,11F0")); + decoder.setModelOverride("GV355CEU"); + + verifyAttributes(decoder, buffer( + "+RESP:GTCAN,8020050605,867488060270575,,00,1,FFFFFFFF,8LBETF3W4N0001613,,,22.54,0,,,,,,,7.84,4.61,3.24,3.33,,8080,,,00,0.00,0.00,1,14,14,2371,0,001FFFFF,,,,,,,,,7158,9998,0,7.84,0.00,0.00,558,,,,,,,C0,,,,,0,0.0,346,2848.5,-78.592371,-0.968132,20240202083437,0740,0002,526C,00AE7907,00,20240202083440,3F6D$")); + } } -- cgit v1.2.3 From 2ab6df0a53e299f5cd6ef880c70054547d07fe42 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 22 Feb 2024 07:17:51 -0800 Subject: Fix SL44/SL48 alarms decoding --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 13 +++++++++---- .../java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 7ee47dd86..6c0380278 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -344,7 +344,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { int mcc = buf.readUnsignedShort(); int mnc; - if (BitUtil.check(mcc, 15) || type == MSG_GPS_LBS_6) { + if (BitUtil.check(mcc, 15) || type == MSG_GPS_LBS_6 || variant == Variant.SL4X) { mnc = buf.readUnsignedShort(); } else { mnc = buf.readUnsignedByte(); @@ -441,15 +441,18 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return Position.ALARM_REMOVING; case 0x23: return Position.ALARM_FALL_DOWN; + case 0x28: + return Position.ALARM_BRAKING; case 0x29: return Position.ALARM_ACCELERATION; - case 0x30: - return Position.ALARM_BRAKING; case 0x2A: case 0x2B: + case 0x2E: return Position.ALARM_CORNERING; case 0x2C: return Position.ALARM_ACCIDENT; + case 0x30: + return Position.ALARM_JAMMING; default: return null; } @@ -1477,6 +1480,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.JC400; } else if (header == 0x7878 && type == MSG_LBS_3 && length == 0x37) { variant = Variant.SL4X; + } else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_4 && length == 0x27) { + variant = Variant.SL4X; } else if (header == 0x7878 && type == MSG_GPS_LBS_2 && length == 0x2f) { variant = Variant.SEEWORLD; } else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_1 && length == 0x26) { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index be8f4f5ef..04d7fafb3 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78782732180214123324ca0162bdf0041f45d900190b0a02d4000bc5270000ec025206040202005e07e10d0a"), + Position.KEY_ALARM, Position.ALARM_POWER_CUT); + verifyAttribute(decoder, binary( "78782616170A080C0E24C0027C58AD0C2B8B0100454E0901CC0025030328E7A0005D4B13021EC373170D0A"), Position.KEY_BATTERY_LEVEL, 93); -- cgit v1.2.3 From ae0e26dde0aca09c4471bb7ec4fa3479bba5d0ad Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 22 Feb 2024 08:02:43 -0800 Subject: Implement Valtrack-V4 protocol --- setup/default.xml | 1 + .../org/traccar/protocol/ValtrackProtocol.java | 41 +++++++++++ .../traccar/protocol/ValtrackProtocolDecoder.java | 84 ++++++++++++++++++++++ .../protocol/FlespiProtocolDecoderTest.java | 15 ++-- .../protocol/ValtrackProtocolDecoderTest.java | 19 +++++ 5 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/traccar/protocol/ValtrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ValtrackProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/ValtrackProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index b89e3ebef..95bb1f04b 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -297,5 +297,6 @@ 5252 5253 5254 + 5255 diff --git a/src/main/java/org/traccar/protocol/ValtrackProtocol.java b/src/main/java/org/traccar/protocol/ValtrackProtocol.java new file mode 100644 index 000000000..8471a0fd8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ValtrackProtocol.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 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.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class ValtrackProtocol extends BaseProtocol { + + @Inject + public ValtrackProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new ValtrackProtocolDecoder(ValtrackProtocol.this)); + } + }); + } +} diff --git a/src/main/java/org/traccar/protocol/ValtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/ValtrackProtocolDecoder.java new file mode 100644 index 000000000..dc9ca8590 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ValtrackProtocolDecoder.java @@ -0,0 +1,84 @@ +/* + * Copyright 2024 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.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class ValtrackProtocolDecoder extends BaseHttpProtocolDecoder { + + public ValtrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String content = request.content().toString(StandardCharsets.UTF_8); + JsonObject object = Json.createReader(new StringReader(content)).readObject(); + JsonArray messages = object.getJsonArray("resource"); + + List positions = new LinkedList<>(); + for (int i = 0; i < messages.size(); i++) { + + JsonObject message = messages.getJsonObject(i); + String id = message.getString("devid"); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + continue; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(new Date()); + position.setLatitude(Double.parseDouble(message.getString("lat"))); + position.setLongitude(Double.parseDouble(message.getString("lon"))); + String speed = message.getString("speed"); + if (!speed.isEmpty()) { + position.setSpeed(Double.parseDouble(speed)); + } + + position.set(Position.KEY_BATTERY, Double.parseDouble(message.getString("vbat"))); + + positions.add(position); + + } + + sendResponse(channel, HttpResponseStatus.OK); + return positions; + } + +} diff --git a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java index 47a6eab87..79131c483 100644 --- a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java @@ -11,14 +11,15 @@ public class FlespiProtocolDecoderTest extends ProtocolTest { var decoder = inject(new FlespiProtocolDecoder(null)); - verifyPositions(decoder, request(HttpMethod.POST, "/", - buffer("[{\"position.speed\":0,\"position.latitude\":53.90573,\"time.valid.status\":true,\"timestamp\":1506956075,\"position.satellites\":10,\"message.buffered.status\":false,\"business.mode.status\":true,\"gps.status\":true,\"position.longitude\":27.455848,\"position.direction\":0,\"ident\":\"605630\"},{\"siren.status\":false,\"business.mode.status\":true,\"position.satellites\":8,\"timestamp\":1506695785,\"led.status\":false,\"position.latitude\":53.905569,\"position.longitude\":27.455986,\"position.speed\":0,\"gradual.stop.status\":false,\"position.direction\":262.643854,\"hardware.version.enum\":223,\"vehicle.mileage\":160,\"message.buffered.status\":false,\"blinkers.status\":false,\"ident\":\"605630\",\"position.altitude\":233.48,\"immobilizer.status\":false}]"))); + verifyPositions(decoder, request(HttpMethod.POST, "/", buffer( + "[{\"position.speed\":0,\"position.latitude\":53.90573,\"time.valid.status\":true,\"timestamp\":1506956075,\"position.satellites\":10,\"message.buffered.status\":false,\"business.mode.status\":true,\"gps.status\":true,\"position.longitude\":27.455848,\"position.direction\":0,\"ident\":\"605630\"},{\"siren.status\":false,\"business.mode.status\":true,\"position.satellites\":8,\"timestamp\":1506695785,\"led.status\":false,\"position.latitude\":53.905569,\"position.longitude\":27.455986,\"position.speed\":0,\"gradual.stop.status\":false,\"position.direction\":262.643854,\"hardware.version.enum\":223,\"vehicle.mileage\":160,\"message.buffered.status\":false,\"blinkers.status\":false,\"ident\":\"605630\",\"position.altitude\":233.48,\"immobilizer.status\":false}]"))); - verifyPositions(decoder, request(HttpMethod.POST, "/", - buffer("[{\"geofence.inside.status\":false,\"position.valid\":false,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":10.11223,\"refrigerator.sensor.temperature#1\":62.5,\"gnss.antenna.cut.status\":true,\"din\":3,\"ain#3\":0,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":0,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":66.7,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":0,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":68.2,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":68.9,\"ident\":\"605630\",\"timestamp\":946684840,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8165,\"external.powersource.voltage\":15.298,\"gnss.enum\":\"glonass\",\"position.longitude\":20.88774,\"battery.voltage\":4.088,\"refrigerator.sensor.temperature#5\":71.3,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false},{\"geofence.inside.status\":false,\"position.valid\":true,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":57.986744,\"refrigerator.sensor.temperature#1\":74.1,\"gnss.antenna.cut.status\":false,\"ain#3\":0,\"position.hdop\":21.1,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":219,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":70.5,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":5,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":71.3,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":69.3,\"ident\":\"605630\",\"timestamp\":1392272112,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8174,\"external.powersource.voltage\":15.303,\"gnss.enum\":\"glonass\",\"position.longitude\":56.207576,\"battery.voltage\":3.934,\"refrigerator.sensor.temperature#5\":68.1,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false}]"))); + verifyPositions(decoder, request(HttpMethod.POST, "/", buffer( + "[{\"geofence.inside.status\":false,\"position.valid\":false,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":10.11223,\"refrigerator.sensor.temperature#1\":62.5,\"gnss.antenna.cut.status\":true,\"din\":3,\"ain#3\":0,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":0,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":66.7,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":0,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":68.2,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":68.9,\"ident\":\"605630\",\"timestamp\":946684840,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8165,\"external.powersource.voltage\":15.298,\"gnss.enum\":\"glonass\",\"position.longitude\":20.88774,\"battery.voltage\":4.088,\"refrigerator.sensor.temperature#5\":71.3,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false},{\"geofence.inside.status\":false,\"position.valid\":true,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":57.986744,\"refrigerator.sensor.temperature#1\":74.1,\"gnss.antenna.cut.status\":false,\"ain#3\":0,\"position.hdop\":21.1,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":219,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":70.5,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":5,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":71.3,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":69.3,\"ident\":\"605630\",\"timestamp\":1392272112,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8174,\"external.powersource.voltage\":15.303,\"gnss.enum\":\"glonass\",\"position.longitude\":56.207576,\"battery.voltage\":3.934,\"refrigerator.sensor.temperature#5\":68.1,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false}]"))); + + verifyPositions(decoder, request(HttpMethod.POST, "/", buffer( + "[{\"ain#1\":1,\"ain#2\":0,\"ain#3\":0,\"ain#4\":0,\"alarm.event.trigger\":true,\"custom.SOS\":1,\"custom.dparam\":3.141593,\"custom.ign\":1,\"custom.iparam\":-55,\"custom.tparam\":\"lorem\",\"din\":722,\"dout\":1048576,\"ident\":\"namo:namo\",\"position.altitude\":300,\"position.direction\":0,\"position.hdop\":1.1,\"position.latitude\":53.90821,\"position.longitude\":27.524165,\"position.satellites\":7,\"position.speed\":0,\"timestamp\":1508508510.013227}]"))); - verifyPositions(decoder, request(HttpMethod.POST, "/", - buffer("[{\"ain#1\":1,\"ain#2\":0,\"ain#3\":0,\"ain#4\":0,\"alarm.event.trigger\":true,\"custom.SOS\":1,\"custom.dparam\":3.141593,\"custom.ign\":1,\"custom.iparam\":-55,\"custom.tparam\":\"lorem\",\"din\":722,\"dout\":1048576,\"ident\":\"namo:namo\",\"position.altitude\":300,\"position.direction\":0,\"position.hdop\":1.1,\"position.latitude\":53.90821,\"position.longitude\":27.524165,\"position.satellites\":7,\"position.speed\":0,\"timestamp\":1508508510.013227}]"))); } -} \ No newline at end of file +} diff --git a/src/test/java/org/traccar/protocol/ValtrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ValtrackProtocolDecoderTest.java new file mode 100644 index 000000000..d526ea850 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ValtrackProtocolDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class ValtrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new ValtrackProtocolDecoder(null)); + + verifyPositions(decoder, request(HttpMethod.POST, "/", buffer( + "{\"resource\":[{\"devid\":\"869731054075783\",\"etype\":\"G_PING\",\"lat\":\"0.000000\",\"lon\":\"0.000000\",\"vbat\":\"12.263848\",\"speed\":\"\",\"nlat\":\"4255.364258\",\"nlon\":\"176.867203\",\"ncsq\":\"16,99\"},{\"devid\":\"869731054075783\",\"etype\":\"G_PING\",\"lat\":\"0.000000\",\"lon\":\"0.000000\",\"vbat\":\"12.263848\",\"speed\":\"\",\"nlat\":\"4255.364258\",\"nlon\":\"176.867203\",\"ncsq\":\"16,99\"},{\"devid\":\"869731054075783\",\"etype\":\"G_PING\",\"lat\":\"0.000000\",\"lon\":\"0.000000\",\"vbat\":\"12.263848\",\"speed\":\"\",\"nlat\":\"4255.364258\",\"nlon\":\"176.867203\",\"ncsq\":\"16,99\"}]}"))); + + } + +} -- cgit v1.2.3 From 500a312d968b5e0a59ba2218df09b9e4c22ea1d4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 23 Feb 2024 07:19:13 -0800 Subject: Support Vista Trax TS15 format --- src/main/java/org/traccar/protocol/TaipProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java index e953756b5..448d7ffca 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -48,7 +48,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .groupEnd("?") .number("(d{5})") // seconds .or() - .expression("(?:RGP|RCQ|RCV|RBR|RUS00),?") // type + .expression("(?:RGP|RCQ|RCV|RBR|RUS00|RPI),?") // type .number("(dd)?") // event .number("(dd)(dd)(dd)") // date (mmddyy) .number("(dd)(dd)(dd)") // time (hhmmss) diff --git a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java index 3ad234b19..197e30c15 100644 --- a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java @@ -11,6 +11,12 @@ public class TaipProtocolDecoderTest extends ProtocolTest { var decoder = inject(new TaipProtocolDecoder(null)); + verifyAttributes(decoder, text( + ">RUS00,010170000000+0000000+000000000000001009999000011060074755268EF,0001139503871486,01,ZZZZZZZZZZ;ID=11817;#LOG:6AE4;*2C<")); + + verifyPosition(decoder, text( + ">RPI041220132203-2683525-065204060150001050000101511140022118857EF27;ID=0000;#LOG:DECB;*07<")); + verifyPosition(decoder, text( ">RCQ00151123235718-2782354-06407582055121FF0013501CDCC6313011100001514;#0805;ID=SIA056;*15<")); -- cgit v1.2.3 From 77b3f9f4b05dfc44809b578eaae55645f496b65c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 24 Feb 2024 16:58:07 -0800 Subject: Refactor notificator classes --- .../traccar/notification/NotificationMessage.java | 6 ++-- .../java/org/traccar/notificators/Notificator.java | 23 ++++++++++++-- .../traccar/notificators/NotificatorCommand.java | 5 +-- .../traccar/notificators/NotificatorFirebase.java | 36 ++++++++++------------ .../org/traccar/notificators/NotificatorMail.java | 21 ++++++------- .../traccar/notificators/NotificatorPushover.java | 21 ++++++------- .../org/traccar/notificators/NotificatorSms.java | 19 +++++------- .../traccar/notificators/NotificatorTelegram.java | 21 ++++++------- .../traccar/notificators/NotificatorTraccar.java | 12 +++----- .../org/traccar/notificators/NotificatorWeb.java | 5 +-- 10 files changed, 86 insertions(+), 83 deletions(-) diff --git a/src/main/java/org/traccar/notification/NotificationMessage.java b/src/main/java/org/traccar/notification/NotificationMessage.java index 0fb8d7654..ca849385a 100644 --- a/src/main/java/org/traccar/notification/NotificationMessage.java +++ b/src/main/java/org/traccar/notification/NotificationMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +18,8 @@ package org.traccar.notification; public class NotificationMessage { - private String subject; - private String body; + private final String subject; + private final String body; public NotificationMessage(String subject, String body) { this.subject = subject; diff --git a/src/main/java/org/traccar/notificators/Notificator.java b/src/main/java/org/traccar/notificators/Notificator.java index cf71141c0..59216b1b6 100644 --- a/src/main/java/org/traccar/notificators/Notificator.java +++ b/src/main/java/org/traccar/notificators/Notificator.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,9 +21,26 @@ import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; +import org.traccar.notification.NotificationFormatter; +import org.traccar.notification.NotificationMessage; -public interface Notificator { +public abstract class Notificator { - void send(Notification notification, User user, Event event, Position position) throws MessageException; + private final NotificationFormatter notificationFormatter; + private final String templatePath; + + public Notificator(NotificationFormatter notificationFormatter, String templatePath) { + this.notificationFormatter = notificationFormatter; + this.templatePath = templatePath; + } + + public void send(Notification notification, User user, Event event, Position position) throws MessageException { + var message = notificationFormatter.formatMessage(notification, user, event, position, templatePath); + send(user, message, event, position); + } + + public void send(User user, NotificationMessage message, Event event, Position position) throws MessageException { + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/org/traccar/notificators/NotificatorCommand.java b/src/main/java/org/traccar/notificators/NotificatorCommand.java index 5dd3313d4..712dda274 100644 --- a/src/main/java/org/traccar/notificators/NotificatorCommand.java +++ b/src/main/java/org/traccar/notificators/NotificatorCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2023 - 2024 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. @@ -31,13 +31,14 @@ import jakarta.inject.Inject; import jakarta.inject.Singleton; @Singleton -public class NotificatorCommand implements Notificator { +public class NotificatorCommand extends Notificator { private final Storage storage; private final CommandsManager commandsManager; @Inject public NotificatorCommand(Storage storage, CommandsManager commandsManager) { + super(null, null); this.storage = storage; this.commandsManager = commandsManager; } diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index 89031ba26..a4171a1d4 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,25 +26,25 @@ import com.google.firebase.messaging.Aps; import com.google.firebase.messaging.FirebaseMessaging; import com.google.firebase.messaging.MessagingErrorCode; import com.google.firebase.messaging.MulticastMessage; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.traccar.model.ObjectOperation; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; -import org.traccar.model.Notification; +import org.traccar.model.ObjectOperation; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; +import org.traccar.notification.NotificationMessage; import org.traccar.session.cache.CacheManager; import org.traccar.storage.Storage; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -54,11 +54,9 @@ import java.util.LinkedList; import java.util.List; @Singleton -public class NotificatorFirebase implements Notificator { +public class NotificatorFirebase extends Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class); - - private final NotificationFormatter notificationFormatter; private final Storage storage; private final CacheManager cacheManager; @@ -67,7 +65,7 @@ public class NotificatorFirebase implements Notificator { Config config, NotificationFormatter notificationFormatter, Storage storage, CacheManager cacheManager) throws IOException { - this.notificationFormatter = notificationFormatter; + super(notificationFormatter, "short"); this.storage = storage; this.cacheManager = cacheManager; @@ -82,18 +80,16 @@ public class NotificatorFirebase implements Notificator { } @Override - public void send(Notification notification, User user, Event event, Position position) throws MessageException { + public void send(User user, NotificationMessage message, Event event, Position position) throws MessageException { if (user.hasAttribute("notificationTokens")) { - var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); - List registrationTokens = new ArrayList<>( Arrays.asList(user.getString("notificationTokens").split("[, ]"))); - MulticastMessage message = MulticastMessage.builder() + var messageBuilder = MulticastMessage.builder() .setNotification(com.google.firebase.messaging.Notification.builder() - .setTitle(shortMessage.getSubject()) - .setBody(shortMessage.getBody()) + .setTitle(message.getSubject()) + .setBody(message.getBody()) .build()) .setAndroidConfig(AndroidConfig.builder() .setNotification(AndroidNotification.builder() @@ -105,12 +101,14 @@ public class NotificatorFirebase implements Notificator { .setSound("default") .build()) .build()) - .addAllTokens(registrationTokens) - .putData("eventId", String.valueOf(event.getId())) - .build(); + .addAllTokens(registrationTokens); + + if (event != null) { + messageBuilder.putData("eventId", String.valueOf(event.getId())); + } try { - var result = FirebaseMessaging.getInstance().sendMulticast(message); + var result = FirebaseMessaging.getInstance().sendMulticast(messageBuilder.build()); List failedTokens = new LinkedList<>(); var iterator = result.getResponses().listIterator(); while (iterator.hasNext()) { diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java index 11d4c5bae..e7ca10157 100644 --- a/src/main/java/org/traccar/notificators/NotificatorMail.java +++ b/src/main/java/org/traccar/notificators/NotificatorMail.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,35 +16,32 @@ */ package org.traccar.notificators; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.mail.MessagingException; import org.traccar.mail.MailManager; import org.traccar.model.Event; -import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import jakarta.mail.MessagingException; +import org.traccar.notification.NotificationMessage; @Singleton -public class NotificatorMail implements Notificator { +public class NotificatorMail extends Notificator { private final MailManager mailManager; - private final NotificationFormatter notificationFormatter; @Inject public NotificatorMail(MailManager mailManager, NotificationFormatter notificationFormatter) { + super(notificationFormatter, "full"); this.mailManager = mailManager; - this.notificationFormatter = notificationFormatter; } @Override - public void send(Notification notification, User user, Event event, Position position) throws MessageException { + public void send(User user, NotificationMessage message, Event event, Position position) throws MessageException { try { - var fullMessage = notificationFormatter.formatMessage(notification, user, event, position, "full"); - mailManager.sendMessage(user, false, fullMessage.getSubject(), fullMessage.getBody()); + mailManager.sendMessage(user, false, message.getSubject(), message.getBody()); } catch (MessagingException e) { throw new MessageException(e); } diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index cf4c4026b..a9708818b 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2024 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. @@ -16,23 +16,21 @@ package org.traccar.notificators; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; -import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.Entity; +import org.traccar.notification.NotificationMessage; @Singleton -public class NotificatorPushover implements Notificator { +public class NotificatorPushover extends Notificator { - private final NotificationFormatter notificationFormatter; private final Client client; private final String url; @@ -54,7 +52,7 @@ public class NotificatorPushover implements Notificator { @Inject public NotificatorPushover(Config config, NotificationFormatter notificationFormatter, Client client) { - this.notificationFormatter = notificationFormatter; + super(notificationFormatter, "short"); this.client = client; url = "https://api.pushover.net/1/messages.json"; token = config.getString(Keys.NOTIFICATOR_PUSHOVER_TOKEN); @@ -62,8 +60,7 @@ public class NotificatorPushover implements Notificator { } @Override - public void send(Notification notification, User user, Event event, Position position) { - var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); + public void send(User user, NotificationMessage shortMessage, Event event, Position position) { Message message = new Message(); message.token = token; diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java index ce362290e..a8086adcc 100644 --- a/src/main/java/org/traccar/notificators/NotificatorSms.java +++ b/src/main/java/org/traccar/notificators/NotificatorSms.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,39 +16,36 @@ */ package org.traccar.notificators; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.traccar.database.StatisticsManager; import org.traccar.model.Event; -import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; +import org.traccar.notification.NotificationMessage; import org.traccar.sms.SmsManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - @Singleton -public class NotificatorSms implements Notificator { +public class NotificatorSms extends Notificator { private final SmsManager smsManager; - private final NotificationFormatter notificationFormatter; private final StatisticsManager statisticsManager; @Inject public NotificatorSms( SmsManager smsManager, NotificationFormatter notificationFormatter, StatisticsManager statisticsManager) { + super(notificationFormatter, "short"); this.smsManager = smsManager; - this.notificationFormatter = notificationFormatter; this.statisticsManager = statisticsManager; } @Override - public void send(Notification notification, User user, Event event, Position position) throws MessageException { + public void send(User user, NotificationMessage message, Event event, Position position) throws MessageException { if (user.getPhone() != null) { - var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); statisticsManager.registerSms(); - smsManager.sendMessage(user.getPhone(), shortMessage.getBody(), false); + smsManager.sendMessage(user.getPhone(), message.getBody(), false); } } diff --git a/src/main/java/org/traccar/notificators/NotificatorTelegram.java b/src/main/java/org/traccar/notificators/NotificatorTelegram.java index eaee32810..4c8d7b8aa 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTelegram.java +++ b/src/main/java/org/traccar/notificators/NotificatorTelegram.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2021 Rafael Miquelino (rafaelmiquelino@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,23 +17,21 @@ package org.traccar.notificators; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; -import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.Entity; +import org.traccar.notification.NotificationMessage; @Singleton -public class NotificatorTelegram implements Notificator { +public class NotificatorTelegram extends Notificator { - private final NotificationFormatter notificationFormatter; private final Client client; private final String urlSendText; @@ -65,7 +63,7 @@ public class NotificatorTelegram implements Notificator { @Inject public NotificatorTelegram(Config config, NotificationFormatter notificationFormatter, Client client) { - this.notificationFormatter = notificationFormatter; + super(notificationFormatter, "short"); this.client = client; urlSendText = String.format( "https://api.telegram.org/bot%s/sendMessage", config.getString(Keys.NOTIFICATOR_TELEGRAM_KEY)); @@ -86,8 +84,7 @@ public class NotificatorTelegram implements Notificator { } @Override - public void send(Notification notification, User user, Event event, Position position) { - var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); + public void send(User user, NotificationMessage shortMessage, Event event, Position position) { TextMessage message = new TextMessage(); message.chatId = user.getString("telegramChatId"); diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java index c00e3e029..983c4cda6 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java +++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2024 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. @@ -25,6 +25,7 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.NotificationFormatter; +import org.traccar.notification.NotificationMessage; import org.traccar.session.cache.CacheManager; import org.traccar.storage.Storage; import org.traccar.storage.query.Columns; @@ -43,11 +44,10 @@ import java.util.LinkedList; import java.util.List; @Singleton -public class NotificatorTraccar implements Notificator { +public class NotificatorTraccar extends Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorTraccar.class); - private final NotificationFormatter notificationFormatter; private final Client client; private final Storage storage; private final CacheManager cacheManager; @@ -75,7 +75,7 @@ public class NotificatorTraccar implements Notificator { public NotificatorTraccar( Config config, NotificationFormatter notificationFormatter, Client client, Storage storage, CacheManager cacheManager) { - this.notificationFormatter = notificationFormatter; + super(notificationFormatter, "short"); this.client = client; this.storage = storage; this.cacheManager = cacheManager; @@ -84,11 +84,9 @@ public class NotificatorTraccar implements Notificator { } @Override - public void send(org.traccar.model.Notification notification, User user, Event event, Position position) { + public void send(User user, NotificationMessage shortMessage, Event event, Position position) { if (user.hasAttribute("notificationTokens")) { - var shortMessage = notificationFormatter.formatMessage(notification, user, event, position, "short"); - NotificationObject item = new NotificationObject(); item.title = shortMessage.getSubject(); item.body = shortMessage.getBody(); diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java index 2b9030226..b7bbdac1b 100644 --- a/src/main/java/org/traccar/notificators/NotificatorWeb.java +++ b/src/main/java/org/traccar/notificators/NotificatorWeb.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,13 +27,14 @@ import jakarta.inject.Inject; import jakarta.inject.Singleton; @Singleton -public final class NotificatorWeb implements Notificator { +public final class NotificatorWeb extends Notificator { private final ConnectionManager connectionManager; private final NotificationFormatter notificationFormatter; @Inject public NotificatorWeb(ConnectionManager connectionManager, NotificationFormatter notificationFormatter) { + super(null, null); this.connectionManager = connectionManager; this.notificationFormatter = notificationFormatter; } -- cgit v1.2.3 From b37c5aa05bdd903af998435e073638f42ae9e8d1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 24 Feb 2024 17:23:39 -0800 Subject: Remove unknown template --- .../org/traccar/notification/TextTemplateFormatter.java | 15 ++------------- templates/full/unknown.vm | 7 ------- templates/short/unknown.vm | 2 -- 3 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 templates/full/unknown.vm delete mode 100644 templates/short/unknown.vm diff --git a/src/main/java/org/traccar/notification/TextTemplateFormatter.java b/src/main/java/org/traccar/notification/TextTemplateFormatter.java index ab90d76d4..cc6935982 100644 --- a/src/main/java/org/traccar/notification/TextTemplateFormatter.java +++ b/src/main/java/org/traccar/notification/TextTemplateFormatter.java @@ -75,19 +75,8 @@ public class TextTemplateFormatter { } public Template getTemplate(String name, String path) { - - String templateFilePath; - Template template; - - try { - templateFilePath = Paths.get(path, name + ".vm").toString(); - template = velocityEngine.getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); - } catch (ResourceNotFoundException error) { - LOGGER.warn("Notification template error", error); - templateFilePath = Paths.get(path, "unknown.vm").toString(); - template = velocityEngine.getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); - } - return template; + String templateFilePath = Paths.get(path, name + ".vm").toString(); + return velocityEngine.getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); } public NotificationMessage formatMessage(VelocityContext velocityContext, String name, String templatePath) { diff --git a/templates/full/unknown.vm b/templates/full/unknown.vm deleted file mode 100644 index 566ce0d42..000000000 --- a/templates/full/unknown.vm +++ /dev/null @@ -1,7 +0,0 @@ -#set($subject = "Unknown type") - - - -Unknown type - - diff --git a/templates/short/unknown.vm b/templates/short/unknown.vm deleted file mode 100644 index 2f9d5e3af..000000000 --- a/templates/short/unknown.vm +++ /dev/null @@ -1,2 +0,0 @@ -#set($subject = "Unknown type") -Unknown type -- cgit v1.2.3 From 9e0c4c5504df985f7b0292042be9d58253450b10 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 24 Feb 2024 17:23:53 -0800 Subject: Add API to send messages --- .../traccar/api/resource/NotificationResource.java | 46 +++++++++++++++++----- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java index 2a209efb6..43dc1fa98 100644 --- a/src/main/java/org/traccar/api/resource/NotificationResource.java +++ b/src/main/java/org/traccar/api/resource/NotificationResource.java @@ -15,6 +15,16 @@ */ package org.traccar.api.resource; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.api.ExtendedObjectResource; @@ -23,20 +33,16 @@ import org.traccar.model.Notification; import org.traccar.model.Typed; import org.traccar.model.User; import org.traccar.notification.MessageException; +import org.traccar.notification.NotificationMessage; import org.traccar.notification.NotificatorManager; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -97,4 +103,26 @@ public class NotificationResource extends ExtendedObjectResource { return Response.noContent().build(); } + @POST + @Path("send/{notificator}") + public Response sendMessage( + @PathParam("notificator") String notificator, @QueryParam("userId") List userIds, + NotificationMessage message) throws MessageException, StorageException { + permissionsService.checkAdmin(getUserId()); + List users; + if (userIds.isEmpty()) { + users = storage.getObjects(User.class, new Request(new Columns.All())); + } else { + users = new ArrayList<>(); + for (long userId : userIds) { + users.add(storage.getObject( + User.class, new Request(new Columns.All(), new Condition.Equals("id", userId)))); + } + } + for (User user : users) { + notificatorManager.getNotificator(notificator).send(user, message, null, null); + } + return Response.noContent().build(); + } + } -- cgit v1.2.3 From 88be1a85b5377156ea812cd8faf62002812ac52e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 24 Feb 2024 17:24:55 -0800 Subject: Remove unused import --- src/main/java/org/traccar/notification/TextTemplateFormatter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/notification/TextTemplateFormatter.java b/src/main/java/org/traccar/notification/TextTemplateFormatter.java index cc6935982..adcfc2ab5 100644 --- a/src/main/java/org/traccar/notification/TextTemplateFormatter.java +++ b/src/main/java/org/traccar/notification/TextTemplateFormatter.java @@ -15,10 +15,11 @@ */ package org.traccar.notification; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.tools.generic.DateTool; import org.apache.velocity.tools.generic.NumberTool; import org.slf4j.Logger; @@ -29,8 +30,6 @@ import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.storage.StorageException; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; -- cgit v1.2.3 From f5257e0da276949d43eaa36b9284fc4d59845637 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 25 Feb 2024 06:40:48 -0800 Subject: Replace deprecated method --- src/main/java/org/traccar/notificators/NotificatorFirebase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index a4171a1d4..7440068f8 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -108,7 +108,7 @@ public class NotificatorFirebase extends Notificator { } try { - var result = FirebaseMessaging.getInstance().sendMulticast(messageBuilder.build()); + var result = FirebaseMessaging.getInstance().sendEachForMulticast(messageBuilder.build()); List failedTokens = new LinkedList<>(); var iterator = result.getResponses().listIterator(); while (iterator.hasNext()) { -- cgit v1.2.3 From 89fba5afc13ab885554a8eaab41722f31f3642f4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 25 Feb 2024 16:59:23 -0800 Subject: Update notification message model --- src/main/java/org/traccar/notification/NotificationMessage.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/notification/NotificationMessage.java b/src/main/java/org/traccar/notification/NotificationMessage.java index ca849385a..551a2d823 100644 --- a/src/main/java/org/traccar/notification/NotificationMessage.java +++ b/src/main/java/org/traccar/notification/NotificationMessage.java @@ -16,12 +16,16 @@ */ package org.traccar.notification; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + public class NotificationMessage { private final String subject; private final String body; - public NotificationMessage(String subject, String body) { + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public NotificationMessage(@JsonProperty("subject") String subject, @JsonProperty("body") String body) { this.subject = subject; this.body = body; } -- cgit v1.2.3 From cb20b6984f6cc75e161e37baa6ff8a56a2e246a7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Feb 2024 18:44:07 -0800 Subject: Fix failed login handling --- src/main/java/org/traccar/api/resource/SessionResource.java | 11 ++++++----- .../java/org/traccar/api/security/SecurityRequestFilter.java | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index dc517277e..2f357a309 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -79,8 +79,8 @@ public class SessionResource extends BaseResource { if (token != null) { LoginResult loginResult = loginService.login(token); - User user = loginResult.getUser(); - if (user != null) { + if (loginResult != null) { + User user = loginResult.getUser(); request.getSession().setAttribute(USER_ID_KEY, user.getId()); request.getSession().setAttribute(EXPIRATION_KEY, loginResult.getExpiration()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); @@ -116,9 +116,9 @@ public class SessionResource extends BaseResource { @FormParam("email") String email, @FormParam("password") String password, @FormParam("code") Integer code) throws StorageException { - User user; + LoginResult loginResult; try { - user = loginService.login(email, password, code).getUser(); + loginResult = loginService.login(email, password, code); } catch (CodeRequiredException e) { Response response = Response .status(Response.Status.UNAUTHORIZED) @@ -126,7 +126,8 @@ public class SessionResource extends BaseResource { .build(); throw new WebApplicationException(response); } - if (user != null) { + if (loginResult != null) { + User user = new User(); request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return user; diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index c33a80015..12a5dbecf 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -90,8 +90,8 @@ public class SecurityRequestFilter implements ContainerRequestFilter { String[] auth = decodeBasicAuth(authHeader); loginResult = loginService.login(auth[0], auth[1], null); } - User user = loginResult.getUser(); - if (user != null) { + if (loginResult != null) { + User user = loginResult.getUser(); statisticsManager.registerRequest(user.getId()); securityContext = new UserSecurityContext( new UserPrincipal(user.getId(), loginResult.getExpiration())); -- cgit v1.2.3 From 967d32485fc685774a9cbeba5b42273b0695bcf7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 28 Feb 2024 04:51:20 -0800 Subject: Fix login regression --- src/main/java/org/traccar/api/resource/SessionResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 2f357a309..979b62589 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -127,7 +127,7 @@ public class SessionResource extends BaseResource { throw new WebApplicationException(response); } if (loginResult != null) { - User user = new User(); + User user = loginResult.getUser(); request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request)); return user; -- cgit v1.2.3 From 35829121adea923d0184e88d38939713bd5f9d4a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 28 Feb 2024 05:43:44 -0800 Subject: Initial G1C Pro support --- .../org/traccar/protocol/HuabaoProtocolDecoder.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 2243bd982..7a6c305e1 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -948,6 +948,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int type = buf.readUnsignedByte(); if (type == 0xF0) { + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -1115,6 +1116,24 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } return position; + + } else if (type == 0xFF) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(readDate(buf, deviceSession.get(DeviceSession.KEY_TIMEZONE))); + position.setLatitude(buf.readInt() * 0.000001); + position.setLongitude(buf.readInt() * 0.000001); + position.setAltitude(buf.readShort()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1)); + position.setCourse(buf.readUnsignedShort()); + + // TODO more positions and g sensor data + + return position; + } return null; -- cgit v1.2.3 From 0e77bb0fd407806ce11593db37aa8557101022fe Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 28 Feb 2024 06:06:16 -0800 Subject: Add GV350M series CAN support --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 9 ++++++--- .../java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 8fb30e2ad..0dac0ad70 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -432,8 +432,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMask, 1) && !values[index++].isEmpty()) { position.set(Position.KEY_IGNITION, Integer.parseInt(values[index - 1]) > 0); } - if (BitUtil.check(reportMask, 2)) { - position.set(Position.KEY_OBD_ODOMETER, values[index++]); + if (BitUtil.check(reportMask, 2) && !values[index++].isEmpty()) { + position.set(Position.KEY_OBD_ODOMETER, Integer.parseInt(values[index - 1].substring(1))); } if (BitUtil.check(reportMask, 3) && !values[index++].isEmpty()) { position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index - 1])); @@ -448,7 +448,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index - 1])); } if (BitUtil.check(reportMask, 7) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(values[index - 1].substring(1))); + String value = values[index - 1]; + if (value.startsWith("L/H")) { + position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(value.substring(3))); + } } if (BitUtil.check(reportMask, 8) && !values[index++].isEmpty()) { position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index - 1].substring(1))); diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 6327f6579..a6e1c212f 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttributes(decoder, buffer( + "+RESP:GTCAN,F10413,862599050467479,GV350M,0,1,C18CFDFF,3BKHHZ8X7GF723380,2,H2898058,232160.50,896,0,64,L/H1.5,P99.20,0,40532.95,,,,,,,,,,,1,0.0,234,2812.2,-78.508807,-0.218812,20240226211921,,,,,,20240226211922,DE03$")); + verifyPositions(decoder, buffer( "+RESP:GTFRI,8020040305,866314060272661,,,50,1,1,0.0,0,2957.9,-78.691727,-0.951205,20231227162916,,,,,00,0.0,,,,,100,210100,,,,20231227162916,0117$")); -- cgit v1.2.3 From 6566236b1e769ef3413a1b03bfa6665a54d63371 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 29 Feb 2024 21:04:29 -0800 Subject: Support G1C Pro motion --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 7a6c305e1..0a8540543 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -403,6 +403,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int status = buf.readInt(); position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); + position.set(Position.KEY_MOTION, BitUtil.check(status, 4)); position.set(Position.KEY_BLOCKED, BitUtil.check(status, 10)); position.set(Position.KEY_CHARGE, BitUtil.check(status, 26)); -- cgit v1.2.3 From 16909b99647f969f4b9c2d3e34a7ada6fc220b94 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 1 Mar 2024 07:29:12 -0800 Subject: Fix Mictrack 710 decoding --- src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java | 5 ++++- src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index 4b11cbc74..6be3d2dc3 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -57,11 +57,14 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { .text("#") .number("(?:(dd|dddd)|x*)") // cell or voltage .groupBegin() - .number("#(d+),") // mcc + .text("#") + .groupBegin() + .number("(d+),") // mcc .number("(d+),") // mnc .number("(x+),") // lac .number("(x+)") // cell id .groupEnd("?") + .groupEnd("?") .text("$GPRMC,") .number("(?:(dd)(dd)(dd).d+)?,") // time (hhmmss.sss) .expression("([AVL]),") // validity diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java index 8a7ba84ab..085d6fc5b 100644 --- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java @@ -12,8 +12,8 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tlt2hProtocolDecoder(null)); verifyPositions(decoder, false, text( - "#868105044690301#MT600+#0000#0#0#129#40#0#AUTOLOW#1\r\n" + - "#072030fa20c$GPRMC,,V,,,,,,,,,,A*5C\r\n")); + "#862255061752835#MT710#0000#AUTO#1\r\n" + + "#4106#$GPRMC,151410.00,A,3010.4103,N,08146.2728,W,,214.90,010324,,,A*58\r\n")); verifyPositions(decoder, text( "#868105044690301#MT600+#0000#0#0#143#40#0#AUTO#1\r\n", -- cgit v1.2.3 From ef2fea79f0346d253647e9ba92a0926b0530d49b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Mar 2024 08:03:13 -0800 Subject: Support additional G106 attributes --- .../org/traccar/protocol/KhdProtocolDecoder.java | 22 +++++++++++++++++++--- .../traccar/protocol/KhdProtocolDecoderTest.java | 4 ++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java index dd2e1dbfd..e88b34478 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java @@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -169,7 +170,9 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_FUEL_LEVEL, BitUtil.from(odometer, 16)); } - position.set(Position.KEY_STATUS, buf.readUnsignedInt()); + long status = buf.readUnsignedInt(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 7 + 3 * 8)); + position.set(Position.KEY_STATUS, status); buf.readUnsignedShort(); buf.readUnsignedByte(); @@ -185,8 +188,7 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShort(); // data length int dataType = buf.readUnsignedByte(); - - buf.readUnsignedByte(); // content length + int dataLength = buf.readUnsignedByte(); switch (dataType) { case 0x01: @@ -197,6 +199,20 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() * 100 + buf.readUnsignedByte()); break; + case 0x05: + int sign = buf.readUnsignedByte(); + switch (sign) { + case 1: + position.set("sign", true); + break; + case 2: + position.set("sign", false); + break; + default: + break; + } + position.set(Position.KEY_DRIVER_UNIQUE_ID, BufferUtil.readString(buf, dataLength - 1)); + break; case 0x18: for (int i = 1; i <= 4; i++) { double value = buf.readUnsignedShort(); diff --git a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java index 7cc65002b..3097c02e8 100644 --- a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class KhdProtocolDecoderTest extends ProtocolTest { var decoder = inject(new KhdProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "2929A300403099934C2004030943310000000000000000000000007B0000007FFF0E0000E70014000000000018050B01303030314330334437312102007B2203140DDA610D"), + Position.KEY_DRIVER_UNIQUE_ID, "0001C03D71"); + verifyAttribute(decoder, binary( "2929a3003e1680ba0a2304180759500000000000000000000000007b00000080001914000000000000000000162001641b0b0000249002bc58030001cc46020000e70d"), Position.KEY_BATTERY_LEVEL, 100); -- cgit v1.2.3 From 2eb48daa96fef40fbf092844f4538277235f0419 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Mar 2024 14:45:10 -0800 Subject: Migrate GL200 ACK message --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 76 ++++++++-------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 0dac0ad70..03488f6d5 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -59,44 +59,6 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName())); } - private static final Pattern PATTERN_ACK = new PatternBuilder() - .text("+ACK:GT") - .expression("...,") // type - .expression("(.{6}|.{10}),") // protocol version - .number("(d{15}|x{14}),") // imei - .any().text(",") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); - - private Object decodeAck(Channel channel, SocketAddress remoteAddress, String sentence, String type) { - Parser parser = new Parser(PATTERN_ACK, sentence); - if (parser.matches()) { - String protocolVersion = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - if (type.equals("HBD")) { - if (channel != null) { - parser.skip(6); - channel.writeAndFlush(new NetworkMessage( - "+SACK:GTHBD," + protocolVersion + "," + parser.next() + "$", remoteAddress)); - } - } else { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, parser.nextDateTime()); - position.setValid(false); - position.set(Position.KEY_RESULT, "Command " + type + " accepted"); - return position; - } - } - return null; - } - private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { if (parser.matches()) { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); @@ -129,6 +91,28 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return null; } + private Position decodeAck( + Channel channel, SocketAddress remoteAddress, String[] values, String type) throws Exception { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[2]); + if (deviceSession == null) { + return null; + } + if (type.equals("HBD")) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + "+SACK:GTHBD," + values[1] + "," + values[values.length - 1] + "$", remoteAddress)); + } + } else { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, new SimpleDateFormat("yyyyMMddHHmmss").parse(values[values.length - 2])); + position.setValid(false); + position.set(Position.KEY_RESULT, values[0]); + return position; + } + return null; + } + private static final Pattern PATTERN_INF = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTINF,") .expression("(?:.{6}|.{10})?,") // protocol version @@ -1541,17 +1525,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII); + String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII).replaceAll("\\$$", ""); int typeIndex = sentence.indexOf(":GT"); if (typeIndex < 0) { return null; } + String[] values = sentence.split(","); + Object result; String type = sentence.substring(typeIndex + 3, typeIndex + 6); if (sentence.startsWith("+ACK")) { - result = decodeAck(channel, remoteAddress, sentence, type); + result = decodeAck(channel, remoteAddress, values, type); } else { switch (type) { case "INF": @@ -1634,13 +1620,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } if (channel != null && getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) { - String checksum; - if (sentence.endsWith("$")) { - checksum = sentence.substring(sentence.length() - 1 - 4, sentence.length() - 1); - } else { - checksum = sentence.substring(sentence.length() - 4); - } - channel.writeAndFlush(new NetworkMessage("+SACK:" + checksum + "$", remoteAddress)); + channel.writeAndFlush(new NetworkMessage("+SACK:" + values[values.length - 1] + "$", remoteAddress)); } return result; -- cgit v1.2.3 From 9c8b9ae246d45f5cc3d24fc5e3041076344b9cf6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Mar 2024 17:40:38 -0800 Subject: Refactor GTERI implementation --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 462 +++++++++++---------- .../protocol/Gl200TextProtocolDecoderTest.java | 14 +- 2 files changed, 242 insertions(+), 234 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 03488f6d5..eccb5c007 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -15,15 +15,15 @@ */ package org.traccar.protocol; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.apache.commons.lang3.StringUtils; +import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.helper.DataConverter; -import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.config.Keys; import org.traccar.helper.BitUtil; +import org.traccar.helper.DataConverter; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; @@ -31,15 +31,14 @@ import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; +import org.traccar.session.DeviceSession; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.TimeZone; @@ -50,8 +49,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private boolean ignoreFixTime; + private final DateFormat dateFormat; + public Gl200TextProtocolDecoder(Protocol protocol) { super(protocol); + dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } @Override @@ -59,6 +62,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName())); } + private String getDeviceModel(DeviceSession deviceSession, String value) { + String model = value.isEmpty() ? getDeviceModel(deviceSession) : value; + return model != null ? model.toUpperCase() : ""; + } + private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { if (parser.matches()) { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); @@ -82,7 +90,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private Long parseHours(String hoursString) { - if (hoursString != null) { + if (hoursString != null && !hoursString.isEmpty()) { String[] hours = hoursString.split(":"); return (Integer.parseInt(hours[0]) * 3600L + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60L : 0) @@ -91,13 +99,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return null; } - private Position decodeAck( - Channel channel, SocketAddress remoteAddress, String[] values, String type) throws Exception { + private Position decodeAck(Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[2]); if (deviceSession == null) { return null; } - if (type.equals("HBD")) { + if (values[0].equals("+ACK:GTHBD")) { if (channel != null) { channel.writeAndFlush(new NetworkMessage( "+SACK:GTHBD," + values[1] + "," + values[values.length - 1] + "$", remoteAddress)); @@ -105,7 +112,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } else { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, new SimpleDateFormat("yyyyMMddHHmmss").parse(values[values.length - 2])); + getLastLocation(position, dateFormat.parse(values[values.length - 2])); position.setValid(false); position.set(Position.KEY_RESULT, values[0]); return position; @@ -323,6 +330,59 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } } + private int decodeLocation(Position position, String model, String[] values, int index) throws ParseException { + double hdop = values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]); + position.set(Position.KEY_HDOP, hdop); + + position.setSpeed(UnitsConverter.knotsFromKph( + values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]))); + position.setCourse(values[index++].isEmpty() ? 0 : Integer.parseInt(values[index - 1])); + position.setAltitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1])); + + if (!values[index].isEmpty()) { + position.setValid(true); + position.setLongitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1])); + position.setLatitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1])); + position.setTime(dateFormat.parse(values[index++])); + } else { + index += 3; + getLastLocation(position, null); + } + + Network network = new Network(); + + if (!values[index].isEmpty()) { + network.addCellTower(CellTower.from( + Integer.parseInt(values[index++]), + Integer.parseInt(values[index++]), + Integer.parseInt(values[index++], 16), + Long.parseLong(values[index++], 16))); + } else { + index += 4; + } + + if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) { + position.setNetwork(network); + } + + if (model.startsWith("GL5")) { + index += 1; // csq rssi + index += 1; // csq ber + } + + if (!values[index++].isEmpty()) { + int appendMask = Integer.parseInt(values[index - 1]); + if (BitUtil.check(appendMask, 0)) { + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + } + if (BitUtil.check(appendMask, 1)) { + index += 1; // trigger type + } + } + + return index; + } + private static final Pattern PATTERN_OBD = new PatternBuilder() .text("+RESP:GTOBD,") .expression("(?:.{6}|.{10})?,") // protocol version @@ -392,92 +452,92 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } - private Object decodeCan(Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException { - Position position = new Position(getProtocolName()); - + private Object decodeCan(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException { int index = 0; - String[] values = sentence.split(","); - index += 1; // header index += 1; // protocol version + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]); + if (deviceSession == null) { + return null; + } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - String model = StringUtils.firstNonEmpty(values[index++], getDeviceModel(deviceSession)); + String model = getDeviceModel(deviceSession, v[index++]); index += 1; // report type index += 1; // can bus state - long reportMask = Long.parseLong(values[index++], 16); + long reportMask = Long.parseLong(v[index++], 16); long reportMaskExt = 0; if (BitUtil.check(reportMask, 0)) { - position.set(Position.KEY_VIN, values[index++]); + position.set(Position.KEY_VIN, v[index++]); } - if (BitUtil.check(reportMask, 1) && !values[index++].isEmpty()) { - position.set(Position.KEY_IGNITION, Integer.parseInt(values[index - 1]) > 0); + if (BitUtil.check(reportMask, 1) && !v[index++].isEmpty()) { + position.set(Position.KEY_IGNITION, Integer.parseInt(v[index - 1]) > 0); } - if (BitUtil.check(reportMask, 2) && !values[index++].isEmpty()) { - position.set(Position.KEY_OBD_ODOMETER, Integer.parseInt(values[index - 1].substring(1))); + if (BitUtil.check(reportMask, 2) && !v[index++].isEmpty()) { + position.set(Position.KEY_OBD_ODOMETER, Integer.parseInt(v[index - 1].substring(1))); } - if (BitUtil.check(reportMask, 3) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 3) && !v[index++].isEmpty()) { + position.set(Position.KEY_FUEL_USED, Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 5) && !values[index++].isEmpty()) { - position.set(Position.KEY_RPM, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 5) && !v[index++].isEmpty()) { + position.set(Position.KEY_RPM, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 4) && !values[index++].isEmpty()) { - position.set(Position.KEY_OBD_SPEED, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 4) && !v[index++].isEmpty()) { + position.set(Position.KEY_OBD_SPEED, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 6) && !values[index++].isEmpty()) { - position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 6) && !v[index++].isEmpty()) { + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 7) && !values[index++].isEmpty()) { - String value = values[index - 1]; + if (BitUtil.check(reportMask, 7) && !v[index++].isEmpty()) { + String value = v[index - 1]; if (value.startsWith("L/H")) { position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(value.substring(3))); } } - if (BitUtil.check(reportMask, 8) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index - 1].substring(1))); + if (BitUtil.check(reportMask, 8) && !v[index++].isEmpty()) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(v[index - 1].substring(1))); } - if (BitUtil.check(reportMask, 9) && !values[index++].isEmpty()) { - position.set("range", Long.parseLong(values[index - 1]) * 100); + if (BitUtil.check(reportMask, 9) && !v[index++].isEmpty()) { + position.set("range", Long.parseLong(v[index - 1]) * 100); } - if (BitUtil.check(reportMask, 10) && !values[index++].isEmpty()) { - position.set(Position.KEY_THROTTLE, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 10) && !v[index++].isEmpty()) { + position.set(Position.KEY_THROTTLE, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 11) && !values[index++].isEmpty()) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1]))); + if (BitUtil.check(reportMask, 11) && !v[index++].isEmpty()) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(v[index - 1]))); } - if (BitUtil.check(reportMask, 12) && !values[index++].isEmpty()) { - position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 12) && !v[index++].isEmpty()) { + position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 13) && !values[index++].isEmpty()) { - position.set("idleHours", Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 13) && !v[index++].isEmpty()) { + position.set("idleHours", Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 14) && !values[index++].isEmpty()) { - position.set("idleFuelConsumption", Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 14) && !v[index++].isEmpty()) { + position.set("idleFuelConsumption", Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 15) && !values[index++].isEmpty()) { - position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 15) && !v[index++].isEmpty()) { + position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 16) && !values[index++].isEmpty()) { - position.set("tachographInfo", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 16) && !v[index++].isEmpty()) { + position.set("tachographInfo", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 17) && !values[index++].isEmpty()) { - position.set("indicators", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 17) && !v[index++].isEmpty()) { + position.set("indicators", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 18) && !values[index++].isEmpty()) { - position.set("lights", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 18) && !v[index++].isEmpty()) { + position.set("lights", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 19) && !values[index++].isEmpty()) { - position.set("doors", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 19) && !v[index++].isEmpty()) { + position.set("doors", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 20) && !values[index++].isEmpty()) { - position.set("vehicleOverspeed", Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 20) && !v[index++].isEmpty()) { + position.set("vehicleOverspeed", Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) { - position.set("engineOverspeed", Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 21) && !v[index++].isEmpty()) { + position.set("engineOverspeed", Double.parseDouble(v[index - 1])); } if ("GV350M".equals(model)) { if (BitUtil.check(reportMask, 22)) { @@ -512,20 +572,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { index += 1; // electric report mask } } - if (BitUtil.check(reportMask, 29) && !values[index++].isEmpty()) { - reportMaskExt = Long.parseLong(values[index - 1], 16); + if (BitUtil.check(reportMask, 29) && !v[index++].isEmpty()) { + reportMaskExt = Long.parseLong(v[index - 1], 16); } - if (BitUtil.check(reportMaskExt, 0) && !values[index++].isEmpty()) { - position.set("adBlueLevel", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 0) && !v[index++].isEmpty()) { + position.set("adBlueLevel", Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMaskExt, 1) && !values[index++].isEmpty()) { - position.set("axleWeight1", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 1) && !v[index++].isEmpty()) { + position.set("axleWeight1", Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMaskExt, 2) && !values[index++].isEmpty()) { - position.set("axleWeight3", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 2) && !v[index++].isEmpty()) { + position.set("axleWeight3", Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMaskExt, 3) && !values[index++].isEmpty()) { - position.set("axleWeight4", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 3) && !v[index++].isEmpty()) { + position.set("axleWeight4", Integer.parseInt(v[index - 1])); } if (BitUtil.check(reportMaskExt, 4)) { index += 1; // tachograph overspeed @@ -536,8 +596,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMaskExt, 6)) { index += 1; // tachograph direction } - if (BitUtil.check(reportMaskExt, 7) && !values[index++].isEmpty()) { - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[index - 1]) * 0.001); + if (BitUtil.check(reportMaskExt, 7) && !v[index++].isEmpty()) { + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(v[index - 1]) * 0.001); } if (BitUtil.check(reportMaskExt, 8)) { index += 1; // pedal breaking factor @@ -560,20 +620,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMaskExt, 14)) { index += 1; // total brake application } - if (BitUtil.check(reportMaskExt, 15) && !values[index++].isEmpty()) { - position.set("driver1Card", values[index - 1]); + if (BitUtil.check(reportMaskExt, 15) && !v[index++].isEmpty()) { + position.set("driver1Card", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 16) && !values[index++].isEmpty()) { - position.set("driver2Card", values[index - 1]); + if (BitUtil.check(reportMaskExt, 16) && !v[index++].isEmpty()) { + position.set("driver2Card", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 17) && !values[index++].isEmpty()) { - position.set("driver1Name", values[index - 1]); + if (BitUtil.check(reportMaskExt, 17) && !v[index++].isEmpty()) { + position.set("driver1Name", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 18) && !values[index++].isEmpty()) { - position.set("driver2Name", values[index - 1]); + if (BitUtil.check(reportMaskExt, 18) && !v[index++].isEmpty()) { + position.set("driver2Name", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 19) && !values[index++].isEmpty()) { - position.set("registration", values[index - 1]); + if (BitUtil.check(reportMaskExt, 19) && !v[index++].isEmpty()) { + position.set("registration", v[index - 1]); } if (BitUtil.check(reportMaskExt, 20)) { index += 1; // expansion information @@ -592,17 +652,17 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); if (!"GV355CEU".equals(model) && BitUtil.check(reportMask, 30)) { - while (values[index].isEmpty()) { + while (v[index].isEmpty()) { index += 1; } - position.setValid(Integer.parseInt(values[index++]) > 0); - if (!values[index].isEmpty()) { - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Integer.parseInt(values[index++])); - position.setAltitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setLatitude(Double.parseDouble(values[index++])); - position.setTime(dateFormat.parse(values[index++])); + position.setValid(Integer.parseInt(v[index++]) > 0); + if (!v[index].isEmpty()) { + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(v[index++]))); + position.setCourse(Integer.parseInt(v[index++])); + position.setAltitude(Double.parseDouble(v[index++])); + position.setLongitude(Double.parseDouble(v[index++])); + position.setLatitude(Double.parseDouble(v[index++])); + position.setTime(dateFormat.parse(v[index++])); } else { index += 6; // no location getLastLocation(position, null); @@ -616,33 +676,31 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { index += 1; // reserved } - index = values.length - 2; + index = v.length - 2; if (ignoreFixTime) { - position.setTime(dateFormat.parse(values[index])); + position.setTime(dateFormat.parse(v[index])); } else { - position.setDeviceTime(dateFormat.parse(values[index])); + position.setDeviceTime(dateFormat.parse(v[index])); } return position; } - private void decodeStatus(Position position, Parser parser) { - if (parser.hasNext(3)) { - int ignition = parser.nextHexInt(); - if (BitUtil.check(ignition, 4)) { - position.set(Position.KEY_IGNITION, false); - } else if (BitUtil.check(ignition, 5)) { - position.set(Position.KEY_IGNITION, true); - } - int input = parser.nextHexInt(); - int output = parser.nextHexInt(); - position.set(Position.KEY_INPUT, input); - position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 1)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 2)); - position.set(Position.KEY_OUTPUT, output); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(output, 0)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(output, 1)); - } + private void decodeStatus(Position position, long value) { + long ignition = BitUtil.between(value, 2 * 8, 3 * 8); + if (BitUtil.check(ignition, 4)) { + position.set(Position.KEY_IGNITION, false); + } else if (BitUtil.check(ignition, 5)) { + position.set(Position.KEY_IGNITION, true); + } + long input = BitUtil.between(value, 8, 2 * 8); + long output = BitUtil.to(value, 8); + position.set(Position.KEY_INPUT, input); + position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 1)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 2)); + position.set(Position.KEY_OUTPUT, output); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(output, 0)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(output, 1)); } private static final Pattern PATTERN_FRI = new PatternBuilder() @@ -672,7 +730,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .number("(x+)?,") // adc 1 .number("(x+)?,") // adc 2 .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status + .number("(x{6})?,") // device status .number("(d+)?,") // rpm .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption .number("(d+)?,") // fuel level @@ -746,7 +804,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 2, parser.next()); position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - decodeStatus(position, parser); + if (parser.hasNext()) { + decodeStatus(position, parser.nextHexLong()); + } position.set(Position.KEY_RPM, parser.nextInt()); position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); @@ -773,142 +833,91 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return positions; } - private static final Pattern PATTERN_ERI = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTERI,") - .expression("(?:.{6}|.{10})?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(x{8}),") // mask - .number("(d+)?,") // power - .number("d{1,2},") // report type - .number("d{1,2},") // count - .expression("((?:") - .expression(PATTERN_LOCATION.pattern()) - .expression(")+)") - .groupBegin() - .number("(d{1,7}.d)?,") // odometer - .number("(d{5}:dd:dd)?,") // hour meter - .number("(x+)?,") // adc 1 - .number("(x+)?,").optional() // adc 2 - .groupBegin() - .number("(x+)?,") // adc 3 - .number("(xx),") // inputs - .number("(xx),") // outputs - .or() - .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status - .groupEnd() - .expression("(.*)") // additional data - .or() - .number("d*,,") - .number("(d+),") // battery - .any() - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private Object decodeEri(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_ERI, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + private Object decodeEri(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException { + int index = 0; + index += 1; // header + index += 1; // protocol version + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]); if (deviceSession == null) { return null; } - long mask = parser.nextHexLong(); + String model = getDeviceModel(deviceSession, v[index++]); + long mask = Long.parseLong(v[index++], 16); + Double power = v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001; + index += 1; // report type + int count = Integer.parseInt(v[index++]); LinkedList positions = new LinkedList<>(); - - Integer power = parser.nextInt(); - - Parser itemParser = new Parser(PATTERN_LOCATION, parser.next()); - while (itemParser.find()) { + for (int i = 0; i < count; i++) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - - decodeLocation(position, itemParser); - + index = decodeLocation(position, model, v, index); positions.add(position); } Position position = positions.getLast(); + position.set(Position.KEY_POWER, power); - skipLocation(parser); - - if (power != null) { - position.set(Position.KEY_POWER, power * 0.001); + if (!model.startsWith("GL5")) { + position.set(Position.KEY_ODOMETER, v[index++].isEmpty() ? null : Double.parseDouble(v[index - 1]) * 1000); + position.set(Position.KEY_HOURS, parseHours(v[index++])); + position.set(Position.PREFIX_ADC + 1, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001); + } + if (model.startsWith("GV") && !model.startsWith("GV6")) { + position.set(Position.PREFIX_ADC + 2, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001); } - if (parser.hasNextAny(12)) { - - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - position.set(Position.KEY_HOURS, parseHours(parser.next())); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.PREFIX_ADC + 3, parser.next()); - if (parser.hasNext(2)) { - position.set(Position.KEY_INPUT, parser.nextHexInt()); - position.set(Position.KEY_OUTPUT, parser.nextHexInt()); - } - if (parser.hasNext(4)) { - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - decodeStatus(position, parser); + position.set(Position.KEY_BATTERY_LEVEL, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1])); + if (model.startsWith("GL5")) { + index += 1; // mode selection + position.set(Position.KEY_MOTION, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) > 0); + } else { + if (!v[index++].isEmpty()) { + decodeStatus(position, Long.parseLong(v[index - 1])); } + index += 1; // reserved + } - int index = 0; - String[] data = parser.next().split(","); - - index += 1; // device type - - if (BitUtil.check(mask, 0)) { - position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(data[index++], 16)); - } + if (BitUtil.check(mask, 0)) { + position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(v[index++], 16)); + } - if (BitUtil.check(mask, 1)) { - int deviceCount = Integer.parseInt(data[index++]); - for (int i = 1; i <= deviceCount; i++) { - index += 1; // id - index += 1; // type - if (!data[index++].isEmpty()) { - position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625); - } + if (BitUtil.check(mask, 1)) { + int deviceCount = Integer.parseInt(v[index++]); + for (int i = 1; i <= deviceCount; i++) { + index += 1; // id + index += 1; // type + if (!v[index++].isEmpty()) { + position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(v[index - 1], 16) * 0.0625); } } + } - if (BitUtil.check(mask, 2)) { - index += 1; // can data - } + if (BitUtil.check(mask, 2)) { + index += 1; // can data + } - if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) { - int deviceCount = Integer.parseInt(data[index++]); - for (int i = 1; i <= deviceCount; i++) { - index += 1; // type - if (BitUtil.check(mask, 3)) { - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data[index++])); - } - if (BitUtil.check(mask, 4)) { - index += 1; // volume - } + if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) { + int deviceCount = Integer.parseInt(v[index++]); + for (int i = 1; i <= deviceCount; i++) { + index += 1; // type + if (BitUtil.check(mask, 3)) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(v[index++])); + } + if (BitUtil.check(mask, 4)) { + index += 1; // volume } } - } - if (parser.hasNext()) { - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - } - - decodeDeviceTime(position, parser); + Date time = dateFormat.parse(v[v.length - 2]); if (ignoreFixTime) { + position.setTime(time); positions.clear(); positions.add(position); + } else { + position.setDeviceTime(time); } return positions; @@ -1187,8 +1196,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { String data = Unpooled.wrappedBuffer(DataConverter.parseHex(parser.next())) .toString(StandardCharsets.US_ASCII); if (data.contains("COMB")) { - String[] values = data.split(","); - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[2])); + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data.split(",")[2])); } else { position.set(Position.KEY_RESULT, data); } @@ -1537,7 +1545,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { Object result; String type = sentence.substring(typeIndex + 3, typeIndex + 6); if (sentence.startsWith("+ACK")) { - result = decodeAck(channel, remoteAddress, values, type); + result = decodeAck(channel, remoteAddress, values); } else { switch (type) { case "INF": @@ -1547,7 +1555,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { result = decodeObd(channel, remoteAddress, sentence); break; case "CAN": - result = decodeCan(channel, remoteAddress, sentence); + result = decodeCan(channel, remoteAddress, values); break; case "CTN": case "FRI": @@ -1558,7 +1566,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { result = decodeFri(channel, remoteAddress, sentence); break; case "ERI": - result = decodeEri(channel, remoteAddress, sentence); + result = decodeEri(channel, remoteAddress, values); break; case "IGN": case "IGF": diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index a6e1c212f..2968161c9 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -46,14 +46,14 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTFRI,5E0100,862061048023666,,,12940,10,1,1,0.0,97,179.8,-90.366478,38.735379,20230616183231,0310,0410,6709,03ADF710,00,6223.7,,,,,110000,,,,202306161834$")); verifyAttribute(decoder, buffer( - "+BUFF:GTERI,410502,864802030794634,,00000001,,10,1,1,0.0,0,3027.8,-78.706612,-0.955699,20230418170736,0740,0002,A08C,2AB72D,00,0.0,,,,100,110000,1,0099,20230418171004,8B98$"), + "+BUFF:GTERI,410502,864802030794634,GV75W,00000001,,10,1,1,0.0,0,3027.8,-78.706612,-0.955699,20230418170736,0740,0002,A08C,2AB72D,00,0.0,,,,100,110000,1,0099,20230418171004,8B98$"), Position.KEY_FUEL_LEVEL, 153); verifyPositions(decoder, false, buffer( "+BUFF:GTFRI,2E0503,861106050005423,,,0,1,,,,,,,,,,,,0,0,,98,1,0,,,20200101000001,0083$")); verifyAttribute(decoder, buffer( - "+RESP:GTERI,271002,863457051562823,,00000002,,10,1,1,0.0,15,28.2,-58.695253,-34.625413,20230119193305,0722,0007,1168,16B3BB,00,0.0,,,,99,210100,2,1,28F8A149F69A3C25,1,0190,20230119193314,07C7$"), + "+RESP:GTERI,271002,863457051562823,GV300,00000002,,10,1,1,0.0,15,28.2,-58.695253,-34.625413,20230119193305,0722,0007,1168,16B3BB,00,0.0,,,,99,210100,2,1,28F8A149F69A3C25,1,0190,20230119193314,07C7$"), Position.PREFIX_TEMP + 1, 25.0); verifyAttribute(decoder, buffer( @@ -170,7 +170,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTERI,310603,863286023345490,,00000002,,10,1,2,0.3,0,155.7,8.000000,52.000000,20171215213040,0262,0002,1450,9F13,00,1130.3,00539:27:19,,,110000,2,1,28FFD5239115034E,1,,20171215213041,27C7$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,250C02,868789023691057,,00000019,,10,1,1,0.0,196,2258.0,-99.201807,19.559242,20180214002957,0334,0003,235B,7F8D,00,6786.7,,,,100,110000,1,0394,1,4,100.0,100.0,20180214003006,C72B$")); + "+RESP:GTERI,250C02,868789023691057,GV300,00000019,,10,1,1,0.0,196,2258.0,-99.201807,19.559242,20180214002957,0334,0003,235B,7F8D,00,6786.7,,,,100,110000,1,0394,1,4,100.0,100.0,20180214003006,C72B$")); verifyAttributes(decoder, buffer( "+RESP:GTCAN,310603,863286023335723,gv65,00,1,C03FFFFF,,0,,719601.00,,,,,,,,274.99,179.02,95.98,84761.00,,,0,,0,,,0,0.0,216,29.8,-2.155296,51.899400,20180209172714,0234,0010,53F3,8D38,00,20180211002128,E94E$")); @@ -197,7 +197,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTOBD,360701,864251020253807,LSGTC58UX7Y067312,GV500,0,70FFFF,LSGTC58UX7Y067312,1,12309,983A8140,0,0,33,nan,,0,0,0,,10,0,,0,4.4,0,83.7,36.235142,49.967324,20170829112348,0255,0001,2760,9017,00,690.1,20170829112400,3456$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060502,861074023620928,,00000002,27822,10,1,1,0.0,84,2870.9,-78.531796,-0.277329,20170825045344,,,,,,0.0,01138:30:24,,,83,220104,2,1,28FF2776A2150308,1,FFAD,0,20170825045348,A88C$")); + "+RESP:GTERI,060502,861074023620928,GV300,00000002,27822,10,1,1,0.0,84,2870.9,-78.531796,-0.277329,20170825045344,,,,,,0.0,01138:30:24,,,83,220104,2,1,28FF2776A2150308,1,FFAD,0,20170825045348,A88C$")); verifyAttributes(decoder, buffer( "+RESP:GTINF,280500,A1000043D20139,GL300VC,41,,31,0,0,,,3.87,0,1,1,,,20170802150751,70,,48.0,,,20170802112145,03AC$")); @@ -212,7 +212,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTTRI,862370030005908,1,0,99,1,0.0,354,18.5,18.821100,-34.084002,20170607152024,0655,0001,00DD,1CAE,00,0103010100,20170607172115,3E7D$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060800,861074023677175,,00000002,12351,10,1,1,0.0,0,2862.4,-78.467273,-0.164998,20170529181717,,,,,,0.0,00259:11:50,,,0,210104,2,1,28E17436060000E2,1,015F,0,20170529181723,2824$")); + "+RESP:GTERI,060800,861074023677175,GV300,00000002,12351,10,1,1,0.0,0,2862.4,-78.467273,-0.164998,20170529181717,,,,,,0.0,00259:11:50,,,0,210104,2,1,28E17436060000E2,1,015F,0,20170529181723,2824$")); verifyPosition(decoder, buffer( "+RESP:GTSWG,110100,358688000000158,,1,0,2.1,0,27.1,121.390717,31.164424,20110901073917,0460,0000,1878,0873,,20110901154653,0015$")); @@ -233,7 +233,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTFRI,060228,862894020180553,,14827,10,1,1,3.4,199,409.6,-63.174466,-17.739317,20170407121823,0000,0000,0000,0000,00,15989.5,01070:43:13,13,180,0,220101,,,,20170407081824,9607$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060502,861074023376992,,00000002,27239,10,1,1,0.2,312,183.3,-79.320820,-2.499110,20170401212005,0740,0000,EE4E,C98F,00,0.0,02114:36:35,,,90,220504,2,0,0,20170401212007,9E3D$")); + "+RESP:GTERI,060502,861074023376992,GV300,00000002,27239,10,1,1,0.2,312,183.3,-79.320820,-2.499110,20170401212005,0740,0000,EE4E,C98F,00,0.0,02114:36:35,,,90,220504,2,0,0,20170401212007,9E3D$")); verifyPositions(decoder, buffer( "+RESP:GTFRI,060502,861074023689626,,25202,10,1,1,0.0,0,2744.1,-78.261047,0.023452,20170401211940,,,,,,0.0,00079:19:15,,,51,110000,,,,20170401212003,4DA7$")); @@ -245,7 +245,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTERI,06020B,862170010196747,,00000000,,10,1,2,1.8,0,-2.5,117.198440,31.845219,20120802061037,0460,0000,5663,0358,00,0.0,,,,0,410000,20120802061040,0012$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060502,861074023692562,,00000002,14197,10,1,1,0.2,220,491.8,-79.064212,-2.159754,20170401212007,0740,0000,EE49,CE25,00,0.0,01509:10:58,,,87,220104,2,0,0,20170401212010,D14D$")); + "+RESP:GTERI,060502,861074023692562,GV300,00000002,14197,10,1,1,0.2,220,491.8,-79.064212,-2.159754,20170401212007,0740,0000,EE49,CE25,00,0.0,01509:10:58,,,87,220104,2,0,0,20170401212010,D14D$")); verifyPositions(decoder, buffer( "+RESP:GTFRI,210102,354524044925825,,1,1,1,29,2.8,0,133.7,-90.203063,32.265473,20170318005208,,,,,10800,4,20170318005208,0002$")); -- cgit v1.2.3 From a1c487c1a7a54382dac98f289c0d55f6fb920cce Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Mar 2024 17:53:48 -0800 Subject: Support GV355CEU GTERI messages --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index eccb5c007..2e5ffa8d6 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -876,7 +876,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (!v[index++].isEmpty()) { decodeStatus(position, Long.parseLong(v[index - 1])); } - index += 1; // reserved + index += 1; // reserved / uart device type } if (BitUtil.check(mask, 0)) { diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 2968161c9..d0e2ad046 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyPositions(decoder, buffer( + "+RESP:GTERI,8020050605,867488060225819,GV355CEU,00000106,12390,10,1,1,0.0,37,253.0,10.240915,45.930262,20240226074452,0222,0010,2F31,0063952B,03,7,0,0.0,,,,,100,110000,0,0,1,FFFFF,VR3USHNSSNJ711765,0,H311796,109.40,0,,,,,,,46.54,29.91,16.63,12.88,,8080,,,00,0,20240226074453,2548$")); + verifyAttributes(decoder, buffer( "+RESP:GTCAN,F10413,862599050467479,GV350M,0,1,C18CFDFF,3BKHHZ8X7GF723380,2,H2898058,232160.50,896,0,64,L/H1.5,P99.20,0,40532.95,,,,,,,,,,,1,0.0,234,2812.2,-78.508807,-0.218812,20240226211921,,,,,,20240226211922,DE03$")); -- cgit v1.2.3 From cf85d6ab0b31b7b51a8f55554592c6524ceb3474 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Mar 2024 17:54:57 -0800 Subject: Add GV620MG GTERI test case --- src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index d0e2ad046..b6e50e07d 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyPositions(decoder, buffer( + "+RESP:GTERI,C2010D,869653060009939,GV600M,00000100,,10,1,0,0.0,0,163.9,10.239379,45.931389,20231210233723,0222,0010,2F31,006D7621,,0.0,,,,3,410000,,1,0,6,4,0,,01BF,Sondaporte,EA7D0A3882F6,1,3484,21.81,43,00,00,0,0,0,20240114221802,1875$")); + verifyPositions(decoder, buffer( "+RESP:GTERI,8020050605,867488060225819,GV355CEU,00000106,12390,10,1,1,0.0,37,253.0,10.240915,45.930262,20240226074452,0222,0010,2F31,0063952B,03,7,0,0.0,,,,,100,110000,0,0,1,FFFFF,VR3USHNSSNJ711765,0,H311796,109.40,0,,,,,,,46.54,29.91,16.63,12.88,,8080,,,00,0,20240226074453,2548$")); -- cgit v1.2.3 From f1680218e85ff3310eb5898d8ec28feaac5797c6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 2 Mar 2024 21:31:37 -0800 Subject: Add device export report --- .../org/traccar/api/resource/ReportResource.java | 15 ++++ .../org/traccar/reports/DevicesReportProvider.java | 78 +++++++++++++++++++++ .../traccar/reports/model/DeviceReportItem.java | 48 +++++++++++++ templates/export/devices.xlsx | Bin 0 -> 9282 bytes 4 files changed, 141 insertions(+) create mode 100644 src/main/java/org/traccar/reports/DevicesReportProvider.java create mode 100644 src/main/java/org/traccar/reports/model/DeviceReportItem.java create mode 100644 templates/export/devices.xlsx diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index b4882f219..55a96fa90 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -23,6 +23,7 @@ import org.traccar.model.Position; import org.traccar.model.Report; import org.traccar.model.UserRestrictions; import org.traccar.reports.CombinedReportProvider; +import org.traccar.reports.DevicesReportProvider; import org.traccar.reports.EventsReportProvider; import org.traccar.reports.RouteReportProvider; import org.traccar.reports.StopsReportProvider; @@ -77,6 +78,9 @@ public class ReportResource extends SimpleObjectResource { @Inject private TripsReportProvider tripsReportProvider; + @Inject + private DevicesReportProvider devicesReportProvider; + @Inject private ReportMailer reportMailer; @@ -319,4 +323,15 @@ public class ReportResource extends SimpleObjectResource { return getStopsExcel(deviceIds, groupIds, from, to, type.equals("mail")); } + @Path("devices/{type:xlsx|mail}") + @GET + @Produces(EXCEL) + public Response geDevicesExcel( + @PathParam("type") String type) throws StorageException { + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); + return executeReport(getUserId(), type.equals("mail"), stream -> { + devicesReportProvider.getExcel(stream, getUserId()); + }); + } + } diff --git a/src/main/java/org/traccar/reports/DevicesReportProvider.java b/src/main/java/org/traccar/reports/DevicesReportProvider.java new file mode 100644 index 000000000..7b4294d53 --- /dev/null +++ b/src/main/java/org/traccar/reports/DevicesReportProvider.java @@ -0,0 +1,78 @@ +/* + * Copyright 2024 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.reports; + +import jakarta.inject.Inject; +import org.jxls.util.JxlsHelper; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.helper.model.PositionUtil; +import org.traccar.model.Device; +import org.traccar.model.Message; +import org.traccar.model.User; +import org.traccar.reports.common.ReportUtils; +import org.traccar.reports.model.DeviceReportItem; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.stream.Collectors; + +public class DevicesReportProvider { + + private final Config config; + private final ReportUtils reportUtils; + private final Storage storage; + + @Inject + public DevicesReportProvider(Config config, ReportUtils reportUtils, Storage storage) { + this.config = config; + this.reportUtils = reportUtils; + this.storage = storage; + } + + public Collection getObjects(long userId) throws StorageException { + + var positions = PositionUtil.getLatestPositions(storage, userId).stream() + .collect(Collectors.toMap(Message::getDeviceId, p -> p)); + + return storage.getObjects(Device.class, new Request( + new Columns.All(), + new Condition.Permission(User.class, userId, Device.class))).stream() + .map(device -> new DeviceReportItem(device, positions.get(device.getId()))) + .collect(Collectors.toUnmodifiableList()); + } + + public void getExcel(OutputStream outputStream, long userId) throws StorageException, IOException { + + File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "devices.xlsx").toFile(); + try (InputStream inputStream = new FileInputStream(file)) { + var context = reportUtils.initializeContext(userId); + context.putVar("items", getObjects(userId)); + JxlsHelper.getInstance().setUseFastFormulaProcessor(false) + .processTemplate(inputStream, outputStream, context); + } + } +} diff --git a/src/main/java/org/traccar/reports/model/DeviceReportItem.java b/src/main/java/org/traccar/reports/model/DeviceReportItem.java new file mode 100644 index 000000000..74cd5f32c --- /dev/null +++ b/src/main/java/org/traccar/reports/model/DeviceReportItem.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 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.reports.model; + +import org.traccar.model.Device; +import org.traccar.model.Position; + +public class DeviceReportItem { + + public DeviceReportItem(Device device, Position position) { + this.device = device; + this.position = position; + } + + private Device device; + + public Device getDevice() { + return device; + } + + public void setDevice(Device device) { + this.device = device; + } + + private Position position; + + public Position getPosition() { + return position; + } + + public void setPosition(Position position) { + this.position = position; + } + +} diff --git a/templates/export/devices.xlsx b/templates/export/devices.xlsx new file mode 100644 index 000000000..ab6d9d5be Binary files /dev/null and b/templates/export/devices.xlsx differ -- cgit v1.2.3 From 75b404db5c790bf37c05fabf1cbbd2027ad1db25 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 3 Mar 2024 08:24:49 -0800 Subject: Refactor XRB28 implementation --- .../org/traccar/protocol/Xrb28ProtocolDecoder.java | 51 +++++++++++++++------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java index 88f2d07e5..6033293c4 100644 --- a/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2024 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. @@ -27,6 +27,7 @@ import org.traccar.model.Command; import org.traccar.model.Position; import java.net.SocketAddress; +import java.util.Arrays; import java.util.regex.Pattern; public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { @@ -46,6 +47,7 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { .expression("....,") .expression("..,") // vendor .number("d{15},") // imei + .number("d{12},").optional() // time .expression("..,") // type .number("[01],") // reserved .number("(dd)(dd)(dd).d+,") // time (hhmmss) @@ -67,23 +69,44 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { String sentence = (String) msg; + String[] values = sentence.replaceAll("#$", "").split(","); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(9, 24)); + int index = 0; + String header = values[index++]; + String vendor = values[index++]; + + String imei = values[index++]; + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); if (deviceSession == null) { return null; } - String type = sentence.substring(25, 27); + String time; + if (values[index].length() == 12) { + time = values[index++]; + } else { + time = null; + } + + String type = values[index++]; if (channel != null) { + StringBuilder response = new StringBuilder("\u00ff\u00ff"); + response.append(header.replaceAll("R$", "S")).append(','); + response.append(vendor).append(','); + response.append(imei).append(','); + if (time != null) { + response.append(time).append(','); + } if (type.matches("L0|L1|W0|E1")) { - channel.write(new NetworkMessage( - "\u00ff\u00ff*SCOS" + sentence.substring(5, 27) + "#\n", - remoteAddress)); + response.append(type).append("#\n"); + channel.write(new NetworkMessage(response.toString(), remoteAddress)); } else if (type.equals("R0") && pendingCommand != null) { - String command = pendingCommand.equals(Command.TYPE_ALARM_ARM) ? "L1," : "L0,"; - channel.write(new NetworkMessage( - "\u00ff\u00ff*SCOS" + sentence.substring(5, 25) + command + sentence.substring(30) + "\n", - remoteAddress)); + String command = pendingCommand.equals(Command.TYPE_ALARM_ARM) ? "L1" : "L0"; + response.append(command); + String[] remaining = Arrays.copyOfRange(values, index, values.length); + response.append(String.join(",", remaining)); + response.append("#\n"); + channel.write(new NetworkMessage(response.toString(), remoteAddress)); pendingCommand = null; } } @@ -95,11 +118,6 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); - String payload = sentence.substring(25, 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); @@ -146,7 +164,8 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { case "K0": case "I0": case "M0": - position.set(Position.KEY_RESULT, payload); + String[] remaining = Arrays.copyOfRange(values, index, values.length); + position.set(Position.KEY_RESULT, String.join(",", remaining)); break; default: break; -- cgit v1.2.3