aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--schema/changelog-5.8.xml18
-rw-r--r--schema/changelog-master.xml1
-rw-r--r--src/main/java/org/traccar/BasePipelineFactory.java2
-rw-r--r--src/main/java/org/traccar/api/resource/CommandResource.java2
-rw-r--r--src/main/java/org/traccar/config/Keys.java8
-rw-r--r--src/main/java/org/traccar/handler/FilterHandler.java9
-rw-r--r--src/main/java/org/traccar/handler/GeofenceHandler.java52
-rw-r--r--src/main/java/org/traccar/handler/events/GeofenceEventHandler.java41
-rw-r--r--src/main/java/org/traccar/handler/events/OverspeedEventHandler.java4
-rw-r--r--src/main/java/org/traccar/model/Calendar.java13
-rw-r--r--src/main/java/org/traccar/model/Device.java21
-rw-r--r--src/main/java/org/traccar/model/Position.java16
-rw-r--r--src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java185
-rw-r--r--src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java23
-rw-r--r--src/main/java/org/traccar/reports/common/ReportUtils.java2
-rw-r--r--src/main/java/org/traccar/schedule/TaskReports.java12
-rw-r--r--src/test/java/org/traccar/calendar/CalendarTest.java15
-rw-r--r--src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java3
-rw-r--r--src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java5
-rw-r--r--swagger.json12
20 files changed, 364 insertions, 80 deletions
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.8">
+
+ <changeSet author="author" id="changelog-5.8">
+
+ <dropColumn tableName="tc_devices" columnName="geofenceids" />
+ <addColumn tableName="tc_positions">
+ <column name="geofenceids" type="VARCHAR(128)" />
+ </addColumn>
+
+ </changeSet>
+
+</databaseChangeLog>
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 @@
<include file="changelog-5.5.xml" relativeToChangelogFile="true" />
<include file="changelog-5.6.xml" relativeToChangelogFile="true" />
<include file="changelog-5.7.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.8.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
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<Channel> {
DistanceHandler.class,
RemoteAddressHandler.class,
FilterHandler.class,
+ GeofenceHandler.class,
GeocoderHandler.class,
SpeedLimitHandler.class,
MotionHandler.class,
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<Command> {
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());
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
@@ -1239,6 +1239,14 @@ public final class Keys {
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<Boolean> 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 ");
}
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<Long> 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<Event, Position> 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<Long> currentGeofences = GeofenceUtil.getCurrentGeofences(config, cacheManager, position);
List<Long> 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<Long> 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<Long> newGeofences = new ArrayList<>();
+ if (position.getGeofenceIds() != null) {
+ newGeofences.addAll(position.getGeofenceIds());
+ newGeofences.removeAll(oldGeofences);
+ oldGeofences.removeAll(position.getGeofenceIds());
}
Map<Event, Position> 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/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<VEvent> findEvents(Date date) {
+ private Collection<VEvent> findEvents(Date date) {
if (calendar != null) {
- Period period = new Period(new DateTime(date), Duration.ZERO);
- Filter<VEvent> filter = new Filter<>(new PeriodRule<>(period));
+ var filter = new Filter<VEvent>(new PeriodRule<>(new Period(new DateTime(date), Duration.ZERO)));
return filter.filter(calendar.getComponents(CalendarComponent.VEVENT));
} else {
return List.of();
}
}
+ public Collection<Period> 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/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<Long> geofenceIds;
-
- @QueryIgnore
- public List<Long> getGeofenceIds() {
- return geofenceIds;
- }
-
- public void setGeofenceIds(List<? extends Number> 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 acb1026f2..be995ca2a 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;
@@ -310,6 +312,20 @@ public class Position extends Message {
this.network = network;
}
+ private List<Long> geofenceIds;
+
+ public List<Long> getGeofenceIds() {
+ return geofenceIds;
+ }
+
+ public void setGeofenceIds(List<? extends Number> geofenceIds) {
+ if (geofenceIds != null) {
+ this.geofenceIds = geofenceIds.stream().map(Number::longValue).collect(Collectors.toList());
+ } else {
+ this.geofenceIds = null;
+ }
+ }
+
@JsonIgnore
@QueryIgnore
@Override
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/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/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;
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());
}
}
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"));
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(
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": {}