diff options
7 files changed, 67 insertions, 9 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<Command> { } 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<QueuedCommand> 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..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,20 +51,23 @@ 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); } - 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 +90,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<Command> readQueuedCommands(long deviceId) { @@ -102,10 +109,16 @@ public class CommandsManager implements BroadcastInterface { new Columns.All(), new Condition.Equals("deviceId", deviceId), new Order("id", false, count))); + Map<Event, Position> 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/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 @@ -18,6 +18,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { "78780D01086471700328358100093F040D0A")); verifyAttribute(decoder, binary( + "78782f22170a020b2737cf02c568a8089fc0dc125c4d01369a371b0a6967020000000007327a00000000001500260074544c0d0a"), + "humidity", 53.76); + + verifyAttribute(decoder, binary( "78785995ffff01170719152013df0163d45f041ee52018be002f00876900004556454e545f3836323739383035303137353131325f30303030303030305f323032335f30375f32355f31385f33325f30355f31342e6d70340119d15a0d0a"), Position.KEY_EVENT, 0x69); 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") +<!DOCTYPE html> +<html> +<body> +Device: $device.name<br> +Queued command sent<br> +Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br> +<br> +<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a> +</body> +</html> 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) |