aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-09-25 10:35:20 -0700
committerAnton Tananaev <anton@traccar.org>2022-09-25 10:35:20 -0700
commitfe3d9995cceb2f1530a7c2549ae9a4cf457cb7f0 (patch)
tree36e7d1b457f7c1e8d3b867cd106033d000a59ddf
parentabb26e80a5617424d960a0f7d0b98fcb379a5224 (diff)
downloadtrackermap-server-fe3d9995cceb2f1530a7c2549ae9a4cf457cb7f0.tar.gz
trackermap-server-fe3d9995cceb2f1530a7c2549ae9a4cf457cb7f0.tar.bz2
trackermap-server-fe3d9995cceb2f1530a7c2549ae9a4cf457cb7f0.zip
Persist device state
-rw-r--r--schema/changelog-5.4.xml22
-rw-r--r--schema/changelog-master.xml1
-rw-r--r--src/main/java/org/traccar/handler/events/MotionEventHandler.java84
-rw-r--r--src/main/java/org/traccar/handler/events/OverspeedEventHandler.java80
-rw-r--r--src/main/java/org/traccar/model/Device.java79
-rw-r--r--src/main/java/org/traccar/reports/common/ReportUtils.java16
-rw-r--r--src/main/java/org/traccar/session/ConnectionManager.java10
-rw-r--r--src/main/java/org/traccar/session/state/MotionProcessor.java75
-rw-r--r--src/main/java/org/traccar/session/state/MotionState.java (renamed from src/main/java/org/traccar/session/DeviceState.java)69
-rw-r--r--src/main/java/org/traccar/session/state/OverspeedProcessor.java65
-rw-r--r--src/main/java/org/traccar/session/state/OverspeedState.java88
-rw-r--r--src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java66
-rw-r--r--src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java56
13 files changed, 486 insertions, 225 deletions
diff --git a/schema/changelog-5.4.xml b/schema/changelog-5.4.xml
new file mode 100644
index 000000000..f3a13ef59
--- /dev/null
+++ b/schema/changelog-5.4.xml
@@ -0,0 +1,22 @@
+<?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.4">
+
+ <changeSet author="author" id="changelog-5.4">
+
+ <addColumn tableName="tc_devices">
+ <column name="motionstate" type="BOOLEAN" defaultValueBoolean="false" />
+ <column name="motiontime" type="TIMESTAMP" />
+ <column name="motiondistance" type="DOUBLE" defaultValueNumeric="0" />
+ <column name="overspeedstate" type="BOOLEAN" defaultValueBoolean="false" />
+ <column name="overspeedtime" type="TIMESTAMP" />
+ <column name="overspeedgeofenceid" type="INT" defaultValueNumeric="0" />
+ </addColumn>
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml
index cea15397d..e877c1afd 100644
--- a/schema/changelog-master.xml
+++ b/schema/changelog-master.xml
@@ -34,5 +34,6 @@
<include file="changelog-5.1.xml" relativeToChangelogFile="true" />
<include file="changelog-5.2.xml" relativeToChangelogFile="true" />
<include file="changelog-5.3.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.4.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java
index 234899785..0777f353a 100644
--- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java
@@ -17,14 +17,21 @@
package org.traccar.handler.events;
import io.netty.channel.ChannelHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.reports.common.TripsConfig;
-import org.traccar.session.ConnectionManager;
-import org.traccar.session.DeviceState;
import org.traccar.session.cache.CacheManager;
+import org.traccar.session.state.MotionProcessor;
+import org.traccar.session.state.MotionState;
+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 java.util.Collections;
@@ -33,66 +40,20 @@ import java.util.Map;
@ChannelHandler.Sharable
public class MotionEventHandler extends BaseEventHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MotionEventHandler.class);
+
private final CacheManager cacheManager;
- private final ConnectionManager connectionManager;
+ private final Storage storage;
private final TripsConfig tripsConfig;
@Inject
public MotionEventHandler(
- CacheManager cacheManager, ConnectionManager connectionManager, TripsConfig tripsConfig) {
+ CacheManager cacheManager, Storage storage, TripsConfig tripsConfig) {
this.cacheManager = cacheManager;
- this.connectionManager = connectionManager;
+ this.storage = storage;
this.tripsConfig = tripsConfig;
}
- public Map<Event, Position> updateMotionState(DeviceState deviceState, Position position, boolean newState) {
-
- boolean oldState = deviceState.getMotionState();
- if (oldState == newState) {
- if (deviceState.getMotionTime() != null) {
- long oldTime = deviceState.getMotionTime().getTime();
- long newTime = position.getFixTime().getTime();
-
- double distance = position.getDouble(Position.KEY_TOTAL_DISTANCE) - deviceState.getMotionDistance();
- Boolean ignition = null;
- if (tripsConfig.getUseIgnition() && position.hasAttribute(Position.KEY_IGNITION)) {
- ignition = position.getBoolean(Position.KEY_IGNITION);
- }
-
- boolean generateEvent = false;
- if (newState) {
- if (newTime - oldTime >= tripsConfig.getMinimalTripDuration()
- || distance >= tripsConfig.getMinimalTripDistance()) {
- generateEvent = true;
- }
- } else {
- if (newTime - oldTime >= tripsConfig.getMinimalParkingDuration()
- || ignition != null && !ignition) {
- generateEvent = true;
- }
- }
-
- if (generateEvent) {
-
- String eventType = newState ? Event.TYPE_DEVICE_MOVING : Event.TYPE_DEVICE_STOPPED;
- Event event = new Event(eventType, position);
-
- deviceState.setMotionTime(null);
- deviceState.setMotionDistance(0);
-
- return Collections.singletonMap(event, position);
-
- }
- }
- } else {
- deviceState.setMotionState(newState);
- deviceState.setMotionTime(position.getFixTime());
- deviceState.setMotionDistance(position.getDouble(Position.KEY_TOTAL_DISTANCE));
- }
-
- return null;
- }
-
@Override
protected Map<Event, Position> analyzePosition(Position position) {
@@ -106,10 +67,19 @@ public class MotionEventHandler extends BaseEventHandler {
return null;
}
- DeviceState deviceState = connectionManager.getDeviceState(deviceId);
- var result = updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION));
- connectionManager.setDeviceState(deviceId, deviceState);
- return result;
+ MotionState state = MotionState.fromDevice(device);
+ MotionProcessor.updateState(state, position, position.getBoolean(Position.KEY_MOTION), tripsConfig);
+ if (state.isChanged()) {
+ state.toDevice(device);
+ try {
+ storage.updateObject(device, new Request(
+ new Columns.Include("motionState", "motionTime", "motionDistance"),
+ new Condition.Equals("id", "id")));
+ } catch (StorageException e) {
+ LOGGER.warn("Update device motion error", e);
+ }
+ }
+ return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null;
}
}
diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
index 3984299d7..c03b8eb7b 100644
--- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
@@ -16,81 +16,50 @@
*/
package org.traccar.handler.events;
-import java.util.Collections;
-import java.util.Map;
-
import io.netty.channel.ChannelHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.traccar.config.Config;
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.session.ConnectionManager;
-import org.traccar.session.DeviceState;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
+import org.traccar.session.state.OverspeedProcessor;
+import org.traccar.session.state.OverspeedState;
+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 java.util.Collections;
+import java.util.Map;
@ChannelHandler.Sharable
public class OverspeedEventHandler extends BaseEventHandler {
- public static final String ATTRIBUTE_SPEED = "speed";
+ private static final Logger LOGGER = LoggerFactory.getLogger(OverspeedEventHandler.class);
- private final ConnectionManager connectionManager;
private final CacheManager cacheManager;
+ private final Storage storage;
private final long minimalDuration;
private final boolean preferLowest;
@Inject
- public OverspeedEventHandler(Config config, ConnectionManager connectionManager, CacheManager cacheManager) {
- this.connectionManager = connectionManager;
+ public OverspeedEventHandler(
+ Config config, CacheManager cacheManager, Storage storage) {
this.cacheManager = cacheManager;
+ this.storage = storage;
minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000;
preferLowest = config.getBoolean(Keys.EVENT_OVERSPEED_PREFER_LOWEST);
}
- public Map<Event, Position> updateOverspeedState(
- DeviceState deviceState, Position position, double speedLimit, long geofenceId) {
-
- boolean oldState = deviceState.getOverspeedState();
- if (oldState) {
- boolean newState = position.getSpeed() > speedLimit;
- if (newState) {
- if (deviceState.getOverspeedTime() != null) {
- long oldTime = deviceState.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(deviceState.getOverspeedGeofenceId());
-
- deviceState.setOverspeedTime(null);
- deviceState.setOverspeedGeofenceId(0);
-
- return Collections.singletonMap(event, position);
-
- }
- }
- } else {
- deviceState.setOverspeedState(false);
- deviceState.setOverspeedTime(null);
- deviceState.setOverspeedGeofenceId(0);
- }
- } else if (position != null && position.getSpeed() > speedLimit) {
- deviceState.setOverspeedState(true);
- deviceState.setOverspeedTime(position.getFixTime());
- deviceState.setOverspeedGeofenceId(geofenceId);
- }
-
- return null;
- }
-
@Override
protected Map<Event, Position> analyzePosition(Position position) {
@@ -135,10 +104,19 @@ public class OverspeedEventHandler extends BaseEventHandler {
return null;
}
- DeviceState deviceState = connectionManager.getDeviceState(deviceId);
- var result = updateOverspeedState(deviceState, position, speedLimit, overspeedGeofenceId);
- connectionManager.setDeviceState(deviceId, deviceState);
- return result;
+ OverspeedState state = OverspeedState.fromDevice(device);
+ OverspeedProcessor.updateState(state, position, speedLimit, minimalDuration, overspeedGeofenceId);
+ if (state.isChanged()) {
+ state.toDevice(device);
+ try {
+ storage.updateObject(device, new Request(
+ new Columns.Include("overspeedState", "overspeedTime", "overspeedGeofenceId"),
+ new Condition.Equals("id", "id")));
+ } catch (StorageException e) {
+ LOGGER.warn("Update device overspeed error", e);
+ }
+ }
+ return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null;
}
}
diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java
index f21e5ca84..147b0fd20 100644
--- a/src/main/java/org/traccar/model/Device.java
+++ b/src/main/java/org/traccar/model/Device.java
@@ -19,6 +19,7 @@ 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;
@@ -162,4 +163,82 @@ public class Device extends GroupedModel implements Disableable {
this.expirationTime = expirationTime;
}
+ private boolean motionState;
+
+ @QueryIgnore
+ @JsonIgnore
+ public boolean getMotionState() {
+ return motionState;
+ }
+
+ @JsonIgnore
+ public void setMotionState(boolean motionState) {
+ this.motionState = motionState;
+ }
+
+ private Date motionTime;
+
+ @QueryIgnore
+ @JsonIgnore
+ public Date getMotionTime() {
+ return motionTime;
+ }
+
+ @JsonIgnore
+ public void setMotionTime(Date motionTime) {
+ this.motionTime = motionTime;
+ }
+
+ private double motionDistance;
+
+ @QueryIgnore
+ @JsonIgnore
+ public double getMotionDistance() {
+ return motionDistance;
+ }
+
+ @JsonIgnore
+ public void setMotionDistance(double motionDistance) {
+ this.motionDistance = motionDistance;
+ }
+
+ private boolean overspeedState;
+
+ @QueryIgnore
+ @JsonIgnore
+ public boolean getOverspeedState() {
+ return overspeedState;
+ }
+
+ @JsonIgnore
+ public void setOverspeedState(boolean overspeedState) {
+ this.overspeedState = overspeedState;
+ }
+
+ private Date overspeedTime;
+
+ @QueryIgnore
+ @JsonIgnore
+ public Date getOverspeedTime() {
+ return overspeedTime;
+ }
+
+ @JsonIgnore
+ public void setOverspeedTime(Date overspeedTime) {
+ this.overspeedTime = overspeedTime;
+ }
+
+ private long overspeedGeofenceId;
+
+ @QueryIgnore
+ @JsonIgnore
+ public long getOverspeedGeofenceId() {
+ return overspeedGeofenceId;
+ }
+
+ @JsonIgnore
+ public void setOverspeedGeofenceId(long overspeedGeofenceId) {
+ this.overspeedGeofenceId = overspeedGeofenceId;
+ }
+
}
diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java
index 2bca00df7..57ed4d148 100644
--- a/src/main/java/org/traccar/reports/common/ReportUtils.java
+++ b/src/main/java/org/traccar/reports/common/ReportUtils.java
@@ -30,7 +30,6 @@ import org.traccar.api.security.PermissionsService;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.geocoder.Geocoder;
-import org.traccar.handler.events.MotionEventHandler;
import org.traccar.helper.UnitsConverter;
import org.traccar.helper.model.PositionUtil;
import org.traccar.helper.model.UserUtil;
@@ -43,7 +42,8 @@ import org.traccar.model.User;
import org.traccar.reports.model.BaseReportItem;
import org.traccar.reports.model.StopReportItem;
import org.traccar.reports.model.TripReportItem;
-import org.traccar.session.DeviceState;
+import org.traccar.session.state.MotionProcessor;
+import org.traccar.session.state.MotionState;
import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;
import org.traccar.storage.query.Columns;
@@ -350,17 +350,16 @@ public class ReportUtils {
ArrayList<Position> positions = new ArrayList<>(positionCollection);
if (!positions.isEmpty()) {
boolean trips = reportClass.equals(TripReportItem.class);
- MotionEventHandler motionHandler = new MotionEventHandler(null, null, tripsConfig);
- DeviceState deviceState = new DeviceState();
- deviceState.setMotionState(isMoving(positions, 0, tripsConfig));
+ MotionState motionState = new MotionState();
+ motionState.setMotionState(isMoving(positions, 0, tripsConfig));
- boolean detected = trips == deviceState.getMotionState();
+ boolean detected = trips == motionState.getMotionState();
int startEventIndex = detected ? 0 : -1;
int startNoEventIndex = -1;
for (int i = 0; i < positions.size(); i++) {
boolean motion = isMoving(positions, i, tripsConfig);
- if (deviceState.getMotionState() != motion) {
+ if (motionState.getMotionState() != motion) {
if (motion == trips) {
startEventIndex = detected ? startEventIndex : i;
startNoEventIndex = -1;
@@ -369,7 +368,8 @@ public class ReportUtils {
}
}
- if (motionHandler.updateMotionState(deviceState, positions.get(i), motion) != null) {
+ MotionProcessor.updateState(motionState, positions.get(i), motion, tripsConfig);
+ if (motionState.getEvent() != null) {
if (motion == trips) {
detected = true;
startNoEventIndex = -1;
diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java
index c826b99db..9e50c9ead 100644
--- a/src/main/java/org/traccar/session/ConnectionManager.java
+++ b/src/main/java/org/traccar/session/ConnectionManager.java
@@ -66,8 +66,6 @@ public class ConnectionManager implements BroadcastInterface {
private final Map<Long, DeviceSession> sessionsByDeviceId = new ConcurrentHashMap<>();
private final Map<Endpoint, Map<String, DeviceSession>> sessionsByEndpoint = new ConcurrentHashMap<>();
- private final Map<Long, DeviceState> deviceStates = new ConcurrentHashMap<>();
-
private final Config config;
private final CacheManager cacheManager;
private final Storage storage;
@@ -275,14 +273,6 @@ public class ConnectionManager implements BroadcastInterface {
updateDevice(true, device);
}
- public DeviceState getDeviceState(long deviceId) {
- return deviceStates.computeIfAbsent(deviceId, x -> new DeviceState());
- }
-
- public void setDeviceState(long deviceId, DeviceState deviceState) {
- deviceStates.put(deviceId, deviceState);
- }
-
public synchronized void sendKeepalive() {
for (Set<UpdateListener> userListeners : listeners.values()) {
for (UpdateListener listener : userListeners) {
diff --git a/src/main/java/org/traccar/session/state/MotionProcessor.java b/src/main/java/org/traccar/session/state/MotionProcessor.java
new file mode 100644
index 000000000..b9d706492
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/MotionProcessor.java
@@ -0,0 +1,75 @@
+/*
+ * 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.state;
+
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.reports.common.TripsConfig;
+
+public final class MotionProcessor {
+
+ private MotionProcessor() {
+ }
+
+ public static void updateState(
+ MotionState state, Position position, boolean newState, TripsConfig tripsConfig) {
+
+ state.setEvent(null);
+
+ boolean oldState = state.getMotionState();
+ if (oldState == newState) {
+ if (state.getMotionTime() != null) {
+ long oldTime = state.getMotionTime().getTime();
+ long newTime = position.getFixTime().getTime();
+
+ double distance = position.getDouble(Position.KEY_TOTAL_DISTANCE) - state.getMotionDistance();
+ Boolean ignition = null;
+ if (tripsConfig.getUseIgnition() && position.hasAttribute(Position.KEY_IGNITION)) {
+ ignition = position.getBoolean(Position.KEY_IGNITION);
+ }
+
+ boolean generateEvent = false;
+ if (newState) {
+ if (newTime - oldTime >= tripsConfig.getMinimalTripDuration()
+ || distance >= tripsConfig.getMinimalTripDistance()) {
+ generateEvent = true;
+ }
+ } else {
+ if (newTime - oldTime >= tripsConfig.getMinimalParkingDuration()
+ || ignition != null && !ignition) {
+ generateEvent = true;
+ }
+ }
+
+ if (generateEvent) {
+
+ String eventType = newState ? Event.TYPE_DEVICE_MOVING : Event.TYPE_DEVICE_STOPPED;
+ Event event = new Event(eventType, position);
+
+ state.setMotionTime(null);
+ state.setMotionDistance(0);
+ state.setEvent(event);
+
+ }
+ }
+ } else {
+ state.setMotionState(newState);
+ state.setMotionTime(position.getFixTime());
+ state.setMotionDistance(position.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/DeviceState.java b/src/main/java/org/traccar/session/state/MotionState.java
index 7bf2a62ac..e3ce58ab2 100644
--- a/src/main/java/org/traccar/session/DeviceState.java
+++ b/src/main/java/org/traccar/session/state/MotionState.java
@@ -1,6 +1,5 @@
/*
- * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ * 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.
@@ -14,22 +13,46 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.session;
+package org.traccar.session.state;
+
+import org.traccar.model.Device;
+import org.traccar.model.Event;
import java.util.Date;
-public class DeviceState {
+public class MotionState {
- private boolean motionState;
+ public static MotionState fromDevice(Device device) {
+ MotionState state = new MotionState();
+ state.motionState = device.getMotionState();
+ state.motionTime = device.getMotionTime();
+ state.motionDistance = device.getMotionDistance();
+ return state;
+ }
- public void setMotionState(boolean motionState) {
- this.motionState = motionState;
+ public void toDevice(Device device) {
+ device.setMotionState(motionState);
+ device.setMotionTime(motionTime);
+ device.setMotionDistance(motionDistance);
+ }
+
+ private boolean changed;
+
+ public boolean isChanged() {
+ return changed;
}
+ private boolean motionState;
+
public boolean getMotionState() {
return motionState;
}
+ public void setMotionState(boolean motionState) {
+ this.motionState = motionState;
+ changed = true;
+ }
+
private Date motionTime;
public Date getMotionTime() {
@@ -38,6 +61,7 @@ public class DeviceState {
public void setMotionTime(Date motionTime) {
this.motionTime = motionTime;
+ changed = true;
}
private double motionDistance;
@@ -48,36 +72,17 @@ public class DeviceState {
public void setMotionDistance(double motionDistance) {
this.motionDistance = motionDistance;
+ changed = true;
}
- private boolean overspeedState;
-
- public void setOverspeedState(boolean overspeedState) {
- this.overspeedState = overspeedState;
- }
-
- public boolean getOverspeedState() {
- return overspeedState;
- }
-
- private Date overspeedTime;
-
- public Date getOverspeedTime() {
- return overspeedTime;
- }
-
- public void setOverspeedTime(Date overspeedTime) {
- this.overspeedTime = overspeedTime;
- }
-
- private long overspeedGeofenceId;
+ private Event event;
- public void setOverspeedGeofenceId(long overspeedGeofenceId) {
- this.overspeedGeofenceId = overspeedGeofenceId;
+ public Event getEvent() {
+ return event;
}
- public long getOverspeedGeofenceId() {
- return overspeedGeofenceId;
+ public void setEvent(Event event) {
+ this.event = event;
}
}
diff --git a/src/main/java/org/traccar/session/state/OverspeedProcessor.java b/src/main/java/org/traccar/session/state/OverspeedProcessor.java
new file mode 100644
index 000000000..62f6a3de2
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/OverspeedProcessor.java
@@ -0,0 +1,65 @@
+/*
+ * 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.state;
+
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public final class OverspeedProcessor {
+
+ public static final String ATTRIBUTE_SPEED = "speed";
+
+ private OverspeedProcessor() {
+ }
+
+ public static void updateState(
+ OverspeedState state, Position position, double speedLimit, long minimalDuration, long geofenceId) {
+
+ state.setEvent(null);
+
+ boolean oldState = state.getOverspeedState();
+ 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);
+
+ }
+ }
+ } else {
+ state.setOverspeedState(false);
+ state.setOverspeedTime(null);
+ state.setOverspeedGeofenceId(0);
+ }
+ } else if (position != null && position.getSpeed() > speedLimit) {
+ state.setOverspeedState(true);
+ state.setOverspeedTime(position.getFixTime());
+ state.setOverspeedGeofenceId(geofenceId);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/state/OverspeedState.java b/src/main/java/org/traccar/session/state/OverspeedState.java
new file mode 100644
index 000000000..340ede6d7
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/OverspeedState.java
@@ -0,0 +1,88 @@
+/*
+ * 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.state;
+
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+
+import java.util.Date;
+
+public class OverspeedState {
+
+ public static OverspeedState fromDevice(Device device) {
+ OverspeedState state = new OverspeedState();
+ state.overspeedState = device.getOverspeedState();
+ state.overspeedTime = device.getOverspeedTime();
+ state.overspeedGeofenceId = device.getOverspeedGeofenceId();
+ return state;
+ }
+
+ public void toDevice(Device device) {
+ device.setOverspeedState(overspeedState);
+ device.setOverspeedTime(overspeedTime);
+ device.setOverspeedGeofenceId(overspeedGeofenceId);
+ }
+
+ private boolean changed;
+
+ public boolean isChanged() {
+ return changed;
+ }
+
+ private boolean overspeedState;
+
+ public boolean getOverspeedState() {
+ return overspeedState;
+ }
+
+ public void setOverspeedState(boolean overspeedState) {
+ this.overspeedState = overspeedState;
+ changed = true;
+ }
+
+ private Date overspeedTime;
+
+ public Date getOverspeedTime() {
+ return overspeedTime;
+ }
+
+ public void setOverspeedTime(Date overspeedTime) {
+ this.overspeedTime = overspeedTime;
+ changed = true;
+ }
+
+ private long overspeedGeofenceId;
+
+ public long getOverspeedGeofenceId() {
+ return overspeedGeofenceId;
+ }
+
+ public void setOverspeedGeofenceId(long overspeedGeofenceId) {
+ this.overspeedGeofenceId = overspeedGeofenceId;
+ changed = true;
+ }
+
+ private Event event;
+
+ public Event getEvent() {
+ return event;
+ }
+
+ public void setEvent(Event event) {
+ this.event = event;
+ }
+
+}
diff --git a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java
index 0d4886429..22afbfa52 100644
--- a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java
+++ b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java
@@ -5,7 +5,8 @@ import org.traccar.BaseTest;
import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.reports.common.TripsConfig;
-import org.traccar.session.DeviceState;
+import org.traccar.session.state.MotionProcessor;
+import org.traccar.session.state.MotionState;
import java.text.DateFormat;
import java.text.ParseException;
@@ -28,57 +29,52 @@ public class MotionEventHandlerTest extends BaseTest {
return position;
}
- private void verifyState(DeviceState deviceState, boolean state, long distance) {
- assertEquals(state, deviceState.getMotionState());
- assertEquals(distance, deviceState.getMotionDistance(), 0.1);
+ private void verifyState(MotionState motionState, boolean state, long distance) {
+ assertEquals(state, motionState.getMotionState());
+ assertEquals(distance, motionState.getMotionDistance(), 0.1);
}
@Test
public void testMotionWithPosition() throws ParseException {
- MotionEventHandler motionEventHandler = new MotionEventHandler(
- null, null, new TripsConfig(500, 300000, 300000, 0, false, false, 0.01));
+ TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false, false, 0.01);
- DeviceState deviceState = new DeviceState();
+ MotionState state = new MotionState();
- Position position = position("2017-01-01 00:00:00", false, 0, null);
- assertNull(motionEventHandler.updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION)));
- verifyState(deviceState, false, 0);
+ MotionProcessor.updateState(state, position("2017-01-01 00:00:00", false, 0, null), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 0);
- position = position("2017-01-01 00:02:00", true, 100, null);
- assertNull(motionEventHandler.updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION)));
- verifyState(deviceState, true, 100);
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", true, 100, null), true, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, true, 100);
- position = position("2017-01-01 00:02:00", true, 700, null);
- var events = motionEventHandler.updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION));
- assertEquals(Event.TYPE_DEVICE_MOVING, events.keySet().iterator().next().getType());
- verifyState(deviceState, true, 0);
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", true, 700, null), true, tripsConfig);
+ assertEquals(Event.TYPE_DEVICE_MOVING, state.getEvent().getType());
+ verifyState(state, true, 0);
- position = position("2017-01-01 00:03:00", false, 700, null);
- assertNull(motionEventHandler.updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION)));
- verifyState(deviceState, false, 700);
+ MotionProcessor.updateState(state, position("2017-01-01 00:03:00", false, 700, null), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 700);
- position = position("2017-01-01 00:10:00", false, 700, null);
- events = motionEventHandler.updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION));
- assertEquals(Event.TYPE_DEVICE_STOPPED, events.keySet().iterator().next().getType());
- verifyState(deviceState, false, 0);
+ MotionProcessor.updateState(state, position("2017-01-01 00:10:00", false, 700, null), false, tripsConfig);
+ assertEquals(Event.TYPE_DEVICE_STOPPED, state.getEvent().getType());
+ verifyState(state, false, 0);
}
@Test
public void testStopWithPositionIgnition() throws ParseException {
- MotionEventHandler motionEventHandler = new MotionEventHandler(
- null, null, new TripsConfig(500, 300000, 300000, 0, true, false, 0.01));
+ TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, true, false, 0.01);
- DeviceState deviceState = new DeviceState();
- deviceState.setMotionState(true);
+ MotionState state = new MotionState();
+ state.setMotionState(true);
- Position position = position("2017-01-01 00:00:00", false, 100, true);
- assertNull(motionEventHandler.updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION)));
- verifyState(deviceState, false, 100);
+ MotionProcessor.updateState(state, position("2017-01-01 00:00:00", false, 100, true), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 100);
- position = position("2017-01-01 00:02:00", false, 100, false);
- var events = motionEventHandler.updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION));
- assertEquals(Event.TYPE_DEVICE_STOPPED, events.keySet().iterator().next().getType());
- verifyState(deviceState, false, 0);
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", false, 100, false), false, tripsConfig);
+ assertEquals(Event.TYPE_DEVICE_STOPPED, state.getEvent().getType());
+ verifyState(state, false, 0);
}
}
diff --git a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java
index bbddbae72..ee18ee052 100644
--- a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java
+++ b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java
@@ -2,11 +2,10 @@ package org.traccar.handler.events;
import org.junit.Test;
import org.traccar.BaseTest;
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
import org.traccar.model.Event;
import org.traccar.model.Position;
-import org.traccar.session.DeviceState;
+import org.traccar.session.state.OverspeedProcessor;
+import org.traccar.session.state.OverspeedState;
import java.text.DateFormat;
import java.text.ParseException;
@@ -28,43 +27,36 @@ public class OverspeedEventHandlerTest extends BaseTest {
return position;
}
- private void verifyState(DeviceState deviceState, boolean state, long geofenceId) {
- assertEquals(state, deviceState.getOverspeedState());
- assertEquals(geofenceId, deviceState.getOverspeedGeofenceId());
+ private void verifyState(OverspeedState overspeedState, boolean state, long geofenceId) {
+ assertEquals(state, overspeedState.getOverspeedState());
+ assertEquals(geofenceId, overspeedState.getOverspeedGeofenceId());
}
private void testOverspeedWithPosition(long geofenceId) throws ParseException {
- Config config = new Config();
- config.setString(Keys.EVENT_OVERSPEED_MINIMAL_DURATION, String.valueOf(15));
- config.setString(Keys.EVENT_OVERSPEED_PREFER_LOWEST, String.valueOf(false));
- OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(config, null, null);
+ OverspeedState state = new OverspeedState();
- DeviceState deviceState = new DeviceState();
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:00", 50), 40, 15000, geofenceId);
+ assertNull(state.getEvent());
+ verifyState(state, true, geofenceId);
- Position position = position("2017-01-01 00:00:00", 50);
- assertNull(overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId));
- verifyState(deviceState, true, geofenceId);
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:10", 55), 40, 15000, geofenceId);
+ assertNull(state.getEvent());
- position = position("2017-01-01 00:00:10", 55);
- assertNull(overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId));
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:20", 55), 40, 15000, geofenceId);
+ assertNotNull(state.getEvent());
+ assertEquals(Event.TYPE_DEVICE_OVERSPEED, state.getEvent().getType());
+ assertEquals(55, state.getEvent().getDouble("speed"), 0.1);
+ assertEquals(40, state.getEvent().getDouble("speedLimit"), 0.1);
+ assertEquals(geofenceId, state.getEvent().getGeofenceId());
+ verifyState(state, true, 0);
- position = position("2017-01-01 00:00:20", 55);
- var events = overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId);
- assertNotNull(events);
- Event event = events.keySet().iterator().next();
- assertEquals(Event.TYPE_DEVICE_OVERSPEED, event.getType());
- assertEquals(55, event.getDouble("speed"), 0.1);
- assertEquals(40, event.getDouble("speedLimit"), 0.1);
- assertEquals(geofenceId, event.getGeofenceId());
- verifyState(deviceState, true, 0);
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 55), 40, 15000, geofenceId);
+ assertNull(state.getEvent());
+ verifyState(state, true, 0);
- position = position("2017-01-01 00:00:30", 55);
- assertNull(overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId));
- verifyState(deviceState, true, 0);
-
- position = position("2017-01-01 00:00:30", 30);
- assertNull(overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId));
- verifyState(deviceState, false, 0);
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 30), 40, 15000, geofenceId);
+ assertNull(state.getEvent());
+ verifyState(state, false, 0);
}
@Test