Skip to content

Commit

Permalink
Add basic support of overspeeding inside geofences.
Browse files Browse the repository at this point in the history
  • Loading branch information
Abyss777 committed May 7, 2018
1 parent 4713a11 commit ce26a07
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 17 deletions.
3 changes: 2 additions & 1 deletion src/org/traccar/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ private static void initEventsModule() {
motionEventHandler = new MotionEventHandler(tripsConfig);
overspeedEventHandler = new OverspeedEventHandler(
Context.getConfig().getLong("event.overspeed.minimalDuration") * 1000,
Context.getConfig().getBoolean("event.overspeed.notRepeat"));
Context.getConfig().getBoolean("event.overspeed.notRepeat"),
Context.getConfig().getBoolean("event.overspeed.geofenceMinimal"));
}

public static void init(IdentityManager testIdentityManager) {
Expand Down
41 changes: 37 additions & 4 deletions src/org/traccar/events/OverspeedEventHandler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright 2016 Anton Tananaev ([email protected])
* Copyright 2016 - 2018 Anton Tananaev ([email protected])
* Copyright 2018 Andrey Kunitsyn ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,27 +24,32 @@
import org.traccar.model.Device;
import org.traccar.model.DeviceState;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Position;

public class OverspeedEventHandler extends BaseEventHandler {

public static final String ATTRIBUTE_SPEED_LIMIT = "speedLimit";

private boolean notRepeat;
private boolean geofenceMinimal;
private long minimalDuration;

public OverspeedEventHandler(long minimalDuration, boolean notRepeat) {
public OverspeedEventHandler(long minimalDuration, boolean notRepeat, boolean geofenceMinimal) {
this.notRepeat = notRepeat;
this.minimalDuration = minimalDuration;
this.geofenceMinimal = geofenceMinimal;
}

private Map<Event, Position> newEvent(DeviceState deviceState, double speedLimit) {
Position position = deviceState.getOverspeedPosition();
Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position.getDeviceId(), position.getId());
event.set("speed", deviceState.getOverspeedPosition().getSpeed());
event.set(ATTRIBUTE_SPEED_LIMIT, speedLimit);
event.setGeofenceId(deviceState.getOverspeedGeofenceId());
deviceState.setOverspeedState(notRepeat);
deviceState.setOverspeedPosition(null);
deviceState.setOverspeedGeofenceId(0);
return Collections.singletonMap(event, position);
}

Expand All @@ -61,7 +67,8 @@ public Map<Event, Position> updateOverspeedState(DeviceState deviceState, double
return result;
}

public Map<Event, Position> updateOverspeedState(DeviceState deviceState, Position position, double speedLimit) {
public Map<Event, Position> updateOverspeedState(
DeviceState deviceState, Position position, double speedLimit, long geofenceId) {
Map<Event, Position> result = null;

Boolean oldOverspeed = deviceState.getOverspeedState();
Expand All @@ -71,12 +78,15 @@ public Map<Event, Position> updateOverspeedState(DeviceState deviceState, Positi
if (newOverspeed && !oldOverspeed) {
if (deviceState.getOverspeedPosition() == null) {
deviceState.setOverspeedPosition(position);
deviceState.setOverspeedGeofenceId(geofenceId);
}
} else if (oldOverspeed && !newOverspeed) {
deviceState.setOverspeedState(false);
deviceState.setOverspeedPosition(null);
deviceState.setOverspeedGeofenceId(0);
} else {
deviceState.setOverspeedPosition(null);
deviceState.setOverspeedGeofenceId(0);
}
Position overspeedPosition = deviceState.getOverspeedPosition();
if (overspeedPosition != null) {
Expand All @@ -101,6 +111,28 @@ protected Map<Event, Position> analyzePosition(Position position) {
}

double speedLimit = Context.getDeviceManager().lookupAttributeDouble(deviceId, ATTRIBUTE_SPEED_LIMIT, 0, false);

double geofenceSpeedLimit = 0;
long overspeedGeofenceId = 0;

if (Context.getGeofenceManager() != null) {
for (long geofenceId : device.getGeofenceIds()) {
Geofence geofence = Context.getGeofenceManager().getById(geofenceId);
if (geofence != null) {
double currentSpeedLimit = geofence.getDouble(ATTRIBUTE_SPEED_LIMIT);
if (currentSpeedLimit > 0 && geofenceSpeedLimit == 0
|| geofenceMinimal && currentSpeedLimit < geofenceSpeedLimit
|| !geofenceMinimal && currentSpeedLimit > geofenceSpeedLimit) {
geofenceSpeedLimit = currentSpeedLimit;
overspeedGeofenceId = geofenceId;
}
}
}
}
if (geofenceSpeedLimit > 0) {
speedLimit = geofenceSpeedLimit;
}

if (speedLimit == 0) {
return null;
}
Expand All @@ -110,8 +142,9 @@ protected Map<Event, Position> analyzePosition(Position position) {

if (deviceState.getOverspeedState() == null) {
deviceState.setOverspeedState(position.getSpeed() > speedLimit);
deviceState.setOverspeedGeofenceId(position.getSpeed() > speedLimit ? overspeedGeofenceId : 0);
} else {
result = updateOverspeedState(deviceState, position, speedLimit);
result = updateOverspeedState(deviceState, position, speedLimit, overspeedGeofenceId);
}

Context.getDeviceManager().setDeviceState(deviceId, deviceState);
Expand Down
10 changes: 10 additions & 0 deletions src/org/traccar/model/DeviceState.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,14 @@ public Position getOverspeedPosition() {
return overspeedPosition;
}

private long overspeedGeofenceId;

public void setOverspeedGeofenceId(long overspeedGeofenceId) {
this.overspeedGeofenceId = overspeedGeofenceId;
}

public long getOverspeedGeofenceId() {
return overspeedGeofenceId;
}

}
2 changes: 1 addition & 1 deletion templates/mail/deviceOverspeed.vm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<html>
<body>
Device: $device.name<br>
Exceeds the speed: $speedString<br>
Exceeds the speed: $speedString#{if}($geofence) in $geofence.name#{else}#{end}<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.serverTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
</body>
Expand Down
2 changes: 1 addition & 1 deletion templates/sms/deviceOverspeed.vm
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
#else
#set($speedString = $numberTool.format("0.0 kn", $position.speed))
#end
$device.name exceeds the speed $speedString at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.serverTime, $locale, $timezone)
$device.name exceeds the speed $speedString#{if}($geofence) in $geofence.name#{else}#{end} at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.serverTime, $locale, $timezone)
29 changes: 19 additions & 10 deletions test/org/traccar/events/OverspeedEventHandlerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,61 +26,67 @@ private Date date(String time) throws ParseException {
return dateFormat.parse(time);
}

private void testOverspeedWithPosition(boolean notRepeat) throws Exception {
OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(15000, notRepeat);
private void testOverspeedWithPosition(boolean notRepeat, long geofenceId) throws Exception {
OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(15000, notRepeat, false);

Position position = new Position();
position.setTime(date("2017-01-01 00:00:00"));
position.setSpeed(50);
DeviceState deviceState = new DeviceState();
deviceState.setOverspeedState(false);

Map<Event, Position> events = overspeedEventHandler.updateOverspeedState(deviceState, position, 40);
Map<Event, Position> events = overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId);
assertNull(events);
assertFalse(deviceState.getOverspeedState());
assertEquals(position, deviceState.getOverspeedPosition());
assertEquals(geofenceId, deviceState.getOverspeedGeofenceId());

Position nextPosition = new Position();
nextPosition.setTime(date("2017-01-01 00:00:10"));
nextPosition.setSpeed(55);

events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40);
events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
assertNull(events);

nextPosition.setTime(date("2017-01-01 00:00:20"));

events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40);
events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
assertNotNull(events);
Event event = events.keySet().iterator().next();
assertEquals(Event.TYPE_DEVICE_OVERSPEED, event.getType());
assertEquals(50, event.getDouble("speed"), 0.1);
assertEquals(40, event.getDouble(OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT), 0.1);
assertEquals(geofenceId, event.getGeofenceId());

assertEquals(notRepeat, deviceState.getOverspeedState());
assertNull(deviceState.getOverspeedPosition());
assertEquals(0, deviceState.getOverspeedGeofenceId());

nextPosition.setTime(date("2017-01-01 00:00:30"));
events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40);
events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
assertNull(events);
assertEquals(notRepeat, deviceState.getOverspeedState());

if (notRepeat) {
assertNull(deviceState.getOverspeedPosition());
assertEquals(0, deviceState.getOverspeedGeofenceId());
} else {
assertNotNull(deviceState.getOverspeedPosition());
assertEquals(geofenceId, deviceState.getOverspeedGeofenceId());
}

nextPosition.setTime(date("2017-01-01 00:00:40"));
nextPosition.setSpeed(30);

events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40);
events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
assertNull(events);
assertFalse(deviceState.getOverspeedState());
assertNull(deviceState.getOverspeedPosition());
assertEquals(0, deviceState.getOverspeedGeofenceId());
}

private void testOverspeedWithStatus(boolean notRepeat) throws Exception {
OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(15000, notRepeat);
OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(15000, notRepeat, false);

Position position = new Position();
position.setTime(new Date(System.currentTimeMillis() - 30000));
Expand All @@ -99,8 +105,11 @@ private void testOverspeedWithStatus(boolean notRepeat) throws Exception {

@Test
public void testOverspeedEventHandler() throws Exception {
testOverspeedWithPosition(false);
testOverspeedWithPosition(true);
testOverspeedWithPosition(false, 0);
testOverspeedWithPosition(true, 0);

testOverspeedWithPosition(false, 1);
testOverspeedWithPosition(true, 1);

testOverspeedWithStatus(false);
testOverspeedWithStatus(true);
Expand Down

0 comments on commit ce26a07

Please sign in to comment.