aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--schema/changelog-3.17.xml85
-rw-r--r--schema/changelog-3.3.xml4
-rw-r--r--schema/changelog-master.xml1
-rw-r--r--setup/default.xml2
-rw-r--r--setup/docker/Dockerfile28
-rwxr-xr-xsetup/docker/build.sh31
-rw-r--r--src/org/traccar/Context.java31
-rw-r--r--src/org/traccar/FilterHandler.java21
-rw-r--r--src/org/traccar/api/resource/EventResource.java4
-rw-r--r--src/org/traccar/api/resource/MaintenanceResource.java36
-rw-r--r--src/org/traccar/database/CommandsManager.java7
-rw-r--r--src/org/traccar/database/DataManager.java29
-rw-r--r--src/org/traccar/database/LdapProvider.java2
-rw-r--r--src/org/traccar/database/MaintenancesManager.java27
-rw-r--r--src/org/traccar/database/NotificationManager.java6
-rw-r--r--src/org/traccar/database/PermissionsManager.java15
-rw-r--r--src/org/traccar/events/MaintenanceEventHandler.java55
-rw-r--r--src/org/traccar/geocoder/GeocodeXyzGeocoder.java60
-rw-r--r--src/org/traccar/model/Event.java10
-rw-r--r--src/org/traccar/model/Maintenance.java61
-rw-r--r--src/org/traccar/model/Position.java1
-rw-r--r--src/org/traccar/model/User.java10
-rw-r--r--src/org/traccar/notification/EventForwarder.java8
-rw-r--r--src/org/traccar/notification/NotificationFormatter.java7
-rw-r--r--src/org/traccar/protocol/AquilaProtocolDecoder.java15
-rw-r--r--src/org/traccar/protocol/AtrackFrameDecoder.java4
-rw-r--r--src/org/traccar/protocol/AtrackProtocolDecoder.java98
-rw-r--r--src/org/traccar/protocol/ContinentalProtocol.java2
-rw-r--r--src/org/traccar/protocol/ContinentalProtocolDecoder.java34
-rw-r--r--src/org/traccar/protocol/EelinkProtocolDecoder.java70
-rw-r--r--src/org/traccar/protocol/EskyProtocolDecoder.java33
-rw-r--r--src/org/traccar/protocol/GatorProtocolDecoder.java8
-rw-r--r--src/org/traccar/protocol/Gl200TextProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/H02ProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/L100FrameDecoder.java5
-rw-r--r--src/org/traccar/protocol/L100Protocol.java6
-rw-r--r--src/org/traccar/protocol/L100ProtocolDecoder.java37
-rw-r--r--src/org/traccar/protocol/Pt502Protocol.java1
-rw-r--r--src/org/traccar/protocol/Pt60ProtocolDecoder.java49
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocolDecoder.java10
-rw-r--r--src/org/traccar/protocol/Tk103Protocol.java3
-rw-r--r--src/org/traccar/protocol/Tk103ProtocolEncoder.java2
-rw-r--r--src/org/traccar/protocol/TotemProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/WatchProtocolDecoder.java2
-rw-r--r--src/org/traccar/reports/Events.java22
-rw-r--r--src/org/traccar/reports/ReportUtils.java46
-rw-r--r--src/org/traccar/reports/Summary.java11
-rw-r--r--src/org/traccar/reports/model/BaseReport.java19
-rw-r--r--templates/export/events.xlsxbin12336 -> 8738 bytes
-rw-r--r--templates/export/stops.xlsxbin12870 -> 11699 bytes
-rw-r--r--templates/export/summary.xlsxbin12564 -> 11592 bytes
-rw-r--r--templates/export/trips.xlsxbin13154 -> 9299 bytes
-rw-r--r--templates/mail/maintenance.vm2
-rw-r--r--templates/sms/maintenance.vm2
-rw-r--r--test/org/traccar/geocoder/GeocoderTest.java33
-rw-r--r--test/org/traccar/protocol/AquilaProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/AtrackFrameDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/AtrackProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/EelinkProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/EgtsProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/EskyFrameDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/EskyProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java9
-rw-r--r--test/org/traccar/protocol/H02ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/L100FrameDecoderTest.java10
-rw-r--r--test/org/traccar/protocol/L100ProtocolDecoderTest.java18
-rw-r--r--test/org/traccar/protocol/Pt60ProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Tk103ProtocolEncoderTest.java14
-rw-r--r--test/org/traccar/protocol/TotemProtocolDecoderTest.java3
71 files changed, 885 insertions, 283 deletions
diff --git a/README.md b/README.md
index 1f3264dc6..39f4d12f9 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# [Traccar](https://www.traccar.org)
-[![Build Status](https://travis-ci.org/tananaev/traccar.svg?branch=master)](https://travis-ci.org/tananaev/traccar)
+[![Build Status](https://travis-ci.org/traccar/traccar.svg?branch=master)](https://travis-ci.org/tananaev/traccar)
## Overview
@@ -9,8 +9,6 @@ Traccar is open source server for various GPS tracking devices. Project is writt
Please read [build from source documentation](https://www.traccar.org/build/) on the official website.
-[Docker documentation](https://www.traccar.org/docker/) is also available of the website.
-
## Team
- Anton Tananaev ([anton@traccar.org](mailto:anton@traccar.org))
diff --git a/schema/changelog-3.17.xml b/schema/changelog-3.17.xml
new file mode 100644
index 000000000..54c3db531
--- /dev/null
+++ b/schema/changelog-3.17.xml
@@ -0,0 +1,85 @@
+<?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-3.17">
+
+ <changeSet author="author" id="changelog-3.3-admin">
+
+ <preConditions onFail="MARK_RAN">
+ <not>
+ <columnExists tableName="administrator" columnName="admin" />
+ </not>
+ </preConditions>
+
+ <renameColumn tableName="users" columnDataType="BOOLEAN" oldColumnName="admin" newColumnName="administrator" />
+
+ </changeSet>
+
+ <changeSet author="author" id="changelog-3.17">
+
+ <addColumn tableName="events">
+ <column name="maintenanceid" type="INT" />
+ </addColumn>
+
+ <createTable tableName="maintenances">
+ <column name="id" type="INT" autoIncrement="true">
+ <constraints primaryKey="true" />
+ </column>
+ <column name="name" type="VARCHAR(4000)">
+ <constraints nullable="false" />
+ </column>
+ <column name="type" type="VARCHAR(128)">
+ <constraints nullable="false" />
+ </column>
+ <column name="start" type="DOUBLE" defaultValueNumeric="0">
+ <constraints nullable="false" />
+ </column>
+ <column name="period" type="DOUBLE" defaultValueNumeric="0">
+ <constraints nullable="false" />
+ </column>
+ <column name="attributes" type="VARCHAR(4000)">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <createTable tableName="user_maintenance">
+ <column name="userid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="maintenanceid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="user_maintenance" baseColumnNames="userid" constraintName="fk_user_maintenance_userid" referencedTableName="users" referencedColumnNames="id" onDelete="CASCADE" />
+ <addForeignKeyConstraint baseTableName="user_maintenance" baseColumnNames="maintenanceid" constraintName="fk_user_maintenance_maintenanceid" referencedTableName="maintenances" referencedColumnNames="id" onDelete="CASCADE" />
+
+ <createTable tableName="group_maintenance">
+ <column name="groupid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="maintenanceid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="group_maintenance" baseColumnNames="groupid" constraintName="fk_group_maintenance_groupid" referencedTableName="groups" referencedColumnNames="id" onDelete="CASCADE" />
+ <addForeignKeyConstraint baseTableName="group_maintenance" baseColumnNames="maintenanceid" constraintName="fk_group_maintenance_maintenanceid" referencedTableName="maintenances" referencedColumnNames="id" onDelete="CASCADE" />
+
+ <createTable tableName="device_maintenance">
+ <column name="deviceid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="maintenanceid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="device_maintenance" baseColumnNames="deviceid" constraintName="fk_device_maintenance_deviceid" referencedTableName="devices" referencedColumnNames="id" onDelete="CASCADE" />
+ <addForeignKeyConstraint baseTableName="device_maintenance" baseColumnNames="maintenanceid" constraintName="fk_device_maintenance_maintenanceid" referencedTableName="maintenances" referencedColumnNames="id" onDelete="CASCADE" />
+
+ </changeSet>
+</databaseChangeLog>
diff --git a/schema/changelog-3.3.xml b/schema/changelog-3.3.xml
index 6ed8cecaa..e5f29c661 100644
--- a/schema/changelog-3.3.xml
+++ b/schema/changelog-3.3.xml
@@ -33,7 +33,7 @@
<column name="readonly" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false" />
</column>
- <column name="admin" type="BOOLEAN" defaultValueBoolean="false">
+ <column name="administrator" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false" />
</column>
<column name="map" type="VARCHAR(128)" defaultValue="osm">
@@ -181,7 +181,7 @@
<column name="email" value="admin" />
<column name="hashedpassword" value="D33DCA55ABD4CC5BC76F2BC0B4E603FE2C6F61F4C1EF2D47" />
<column name="salt" value="000000000000000000000000000000000000000000000000" />
- <column name="admin" valueBoolean="true" />
+ <column name="administrator" valueBoolean="true" />
</insert>
</changeSet>
diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml
index 0c6941eed..3e7944238 100644
--- a/schema/changelog-master.xml
+++ b/schema/changelog-master.xml
@@ -17,4 +17,5 @@
<include file="changelog-3.14.xml" relativeToChangelogFile="true" />
<include file="changelog-3.15.xml" relativeToChangelogFile="true" />
<include file="changelog-3.16.xml" relativeToChangelogFile="true" />
+ <include file="changelog-3.17.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git a/setup/default.xml b/setup/default.xml
index 6786d1166..9b05fa85f 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -29,6 +29,8 @@
<entry key='server.statistics'>https://www.traccar.org/analytics/</entry>
+ <entry key='commands.queueing'>true</entry>
+
<!-- DATABASE CONFIG -->
<entry key='database.ignoreUnknown'>true</entry>
diff --git a/setup/docker/Dockerfile b/setup/docker/Dockerfile
deleted file mode 100644
index d86b078c1..000000000
--- a/setup/docker/Dockerfile
+++ /dev/null
@@ -1,28 +0,0 @@
-FROM java:8-alpine
-
-MAINTAINER Danilo Recchia <danilo.recchia@vortus.solutions>
-
-USER root
-
-RUN apk upgrade --update && \
- apk add --update curl bash && \
- rm -rf /var/cache/apk/* && \
- mkdir -p /opt/traccar/logs && \
- mkdir -p /opt/traccar/data
-
-ENV JAVA_OPTS -Xms256m -Xmx1024m
-
-COPY ./tmp/traccar.xml /opt/traccar/traccar.xml
-COPY ./tmp/default.xml /opt/traccar/conf/default.xml
-COPY ./tmp/schema /opt/traccar/schema
-COPY ./tmp/templates /opt/traccar/templates
-COPY ./tmp/web /opt/traccar/web
-COPY ./tmp/lib /opt/traccar/lib
-COPY ./tmp/traccar-server.jar /opt/traccar/traccar-server.jar
-
-EXPOSE 8082
-EXPOSE 5000-5150
-
-WORKDIR /opt/traccar
-
-ENTRYPOINT ["java","-jar","traccar-server.jar","traccar.xml"]
diff --git a/setup/docker/build.sh b/setup/docker/build.sh
deleted file mode 100755
index b4cb75a4a..000000000
--- a/setup/docker/build.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-which mvn &> /dev/null || { echo >&2 "Maven package cant be found on path. Aborting."; exit 1; }
-which awk &> /dev/null || { echo >&2 "Awk package cant be found on path. Aborting."; exit 1; }
-which docker &> /dev/null || { echo >&2 "Docker package cant be found on path. Aborting."; exit 1; }
-mvn package || { echo >&2 "Maven package has failed. Aborting."; exit 1; }
-
-export company=${1:-"tananaev"}
-export software=${2:-"traccar"}
-export _version=$(head -n 10 ./pom.xml |grep version|cut -d ">" -f2|cut -d"<" -f1)
-export version=${3:-$_version}
-
-tmp="./setup/docker/tmp"
-
-mkdir -p ${tmp}
-
-cat ./setup/traccar.xml | awk '/config.default/ && !modif { print;printf(" <entry key=\"web.debug\">true</entry>\n");next; modif=1 } {print}' > ${tmp}/traccar.xml
-cp -rf ./setup/default.xml ${tmp}
-cp -rf ./schema ${tmp}/schema
-cp -rf ./templates ${tmp}/templates
-cp -rf ./target/tracker-server.jar ${tmp}/traccar-server.jar
-cp -rf ./target/lib ${tmp}/lib
-if [ -d ./traccar-web/web ]; then
- cp -rf ./traccar-web/web ${tmp}/web
-else
- mkdir ${tmp}/web
-fi
-
-docker build -t ${company}/${software}:${version} ./setup/docker/
-
-rm -rf ${tmp}
diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java
index 09e3c619b..ee14eb1f7 100644
--- a/src/org/traccar/Context.java
+++ b/src/org/traccar/Context.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2018 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 java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;
+import com.ning.http.client.AsyncHttpClientConfigDefaults;
import org.apache.velocity.app.VelocityEngine;
import org.eclipse.jetty.util.URIUtil;
import org.traccar.database.CalendarManager;
@@ -35,6 +36,7 @@ import org.traccar.database.DeviceManager;
import org.traccar.database.DriversManager;
import org.traccar.database.IdentityManager;
import org.traccar.database.LdapProvider;
+import org.traccar.database.MaintenancesManager;
import org.traccar.database.MediaManager;
import org.traccar.database.NotificationManager;
import org.traccar.database.PermissionsManager;
@@ -48,6 +50,7 @@ import org.traccar.geocoder.AddressFormat;
import org.traccar.geocoder.BingMapsGeocoder;
import org.traccar.geocoder.FactualGeocoder;
import org.traccar.geocoder.GeocodeFarmGeocoder;
+import org.traccar.geocoder.GeocodeXyzGeocoder;
import org.traccar.geocoder.GisgraphyGeocoder;
import org.traccar.geocoder.GoogleGeocoder;
import org.traccar.geocoder.MapQuestGeocoder;
@@ -64,6 +67,7 @@ import org.traccar.model.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.model.Notification;
import org.traccar.model.User;
import org.traccar.geolocation.GoogleGeolocationProvider;
@@ -79,6 +83,9 @@ import org.traccar.web.WebServer;
public final class Context {
+ private static final String USER_AGENT =
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0";
+
private Context() {
}
@@ -202,10 +209,15 @@ public final class Context {
return velocityEngine;
}
- private static final AsyncHttpClient ASYNC_HTTP_CLIENT = new AsyncHttpClient();
+ private static AsyncHttpClient asyncHttpClient;
+
+ static {
+ System.setProperty(AsyncHttpClientConfigDefaults.ASYNC_CLIENT + "userAgent", USER_AGENT);
+ asyncHttpClient = new AsyncHttpClient();
+ }
public static AsyncHttpClient getAsyncHttpClient() {
- return ASYNC_HTTP_CLIENT;
+ return asyncHttpClient;
}
private static EventForwarder eventForwarder;
@@ -232,6 +244,12 @@ public final class Context {
return commandsManager;
}
+ private static MaintenancesManager maintenancesManager;
+
+ public static MaintenancesManager getMaintenancesManager() {
+ return maintenancesManager;
+ }
+
private static StatisticsManager statisticsManager;
public static StatisticsManager getStatisticsManager() {
@@ -303,6 +321,8 @@ public final class Context {
return new FactualGeocoder(url, key, cacheSize, addressFormat);
case "geocodefarm":
return new GeocodeFarmGeocoder(key, language, cacheSize, addressFormat);
+ case "geocodexyz":
+ return new GeocodeXyzGeocoder(key, cacheSize, addressFormat);
default:
return new GoogleGeocoder(key, language, cacheSize, addressFormat);
}
@@ -383,7 +403,7 @@ public final class Context {
driversManager = new DriversManager(dataManager);
- commandsManager = new CommandsManager(dataManager);
+ commandsManager = new CommandsManager(dataManager, config.getBoolean("commands.queueing"));
statisticsManager = new StatisticsManager();
@@ -419,6 +439,7 @@ public final class Context {
geofenceManager = new GeofenceManager(dataManager);
calendarManager = new CalendarManager(dataManager);
+ maintenancesManager = new MaintenancesManager(dataManager);
notificationManager = new NotificationManager(dataManager);
Properties velocityProperties = new Properties();
velocityProperties.setProperty("file.resource.loader.path",
@@ -469,6 +490,8 @@ public final class Context {
return (BaseObjectManager<T>) driversManager;
} else if (clazz.equals(Command.class)) {
return (BaseObjectManager<T>) commandsManager;
+ } else if (clazz.equals(Maintenance.class)) {
+ return (BaseObjectManager<T>) maintenancesManager;
} else if (clazz.equals(Notification.class)) {
return (BaseObjectManager<T>) notificationManager;
}
diff --git a/src/org/traccar/FilterHandler.java b/src/org/traccar/FilterHandler.java
index 93f71d4e1..c6363813c 100644
--- a/src/org/traccar/FilterHandler.java
+++ b/src/org/traccar/FilterHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2018 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 @@ public class FilterHandler extends BaseDataHandler {
private boolean filterStatic;
private int filterDistance;
private int filterMaxSpeed;
+ private long filterMinPeriod;
private long skipLimit;
private boolean skipAttributes;
@@ -69,6 +70,10 @@ public class FilterHandler extends BaseDataHandler {
this.filterMaxSpeed = filterMaxSpeed;
}
+ public void setFilterMinPeriod(int filterMinPeriod) {
+ this.filterMinPeriod = filterMinPeriod;
+ }
+
public void setSkipLimit(long skipLimit) {
this.skipLimit = skipLimit;
}
@@ -89,6 +94,7 @@ public class FilterHandler extends BaseDataHandler {
filterStatic = config.getBoolean("filter.static");
filterDistance = config.getInteger("filter.distance");
filterMaxSpeed = config.getInteger("filter.maxSpeed");
+ filterMinPeriod = config.getInteger("filter.minPeriod") * 1000;
skipLimit = config.getLong("filter.skipLimit") * 1000;
skipAttributes = config.getBoolean("filter.skipAttributes.enable");
}
@@ -148,6 +154,14 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
+ private boolean filterMinPeriod(Position position, Position last) {
+ if (filterMinPeriod != 0 && last != null) {
+ long time = position.getFixTime().getTime() - last.getFixTime().getTime();
+ return time > 0 && time < filterMinPeriod;
+ }
+ return false;
+ }
+
private boolean skipLimit(Position position, Position last) {
if (skipLimit != 0 && last != null) {
return (position.getServerTime().getTime() - last.getServerTime().getTime()) > skipLimit;
@@ -208,6 +222,9 @@ public class FilterHandler extends BaseDataHandler {
if (filterMaxSpeed(position, last)) {
filterType.append("MaxSpeed ");
}
+ if (filterMinPeriod(position, last)) {
+ filterType.append("MinPeriod ");
+ }
if (filterType.length() > 0) {
@@ -216,8 +233,6 @@ public class FilterHandler extends BaseDataHandler {
message.append(filterType.toString());
message.append("filters from device: ");
message.append(Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId());
- message.append(" with id: ");
- message.append(position.getDeviceId());
Log.info(message.toString());
return true;
diff --git a/src/org/traccar/api/resource/EventResource.java b/src/org/traccar/api/resource/EventResource.java
index a7cf9edbd..e0ccf7020 100644
--- a/src/org/traccar/api/resource/EventResource.java
+++ b/src/org/traccar/api/resource/EventResource.java
@@ -13,6 +13,7 @@ import org.traccar.Context;
import org.traccar.api.BaseResource;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
@Path("events")
@Produces(MediaType.APPLICATION_JSON)
@@ -28,6 +29,9 @@ public class EventResource extends BaseResource {
if (event.getGeofenceId() != 0) {
Context.getPermissionsManager().checkPermission(Geofence.class, getUserId(), event.getGeofenceId());
}
+ if (event.getMaintenanceId() != 0) {
+ Context.getPermissionsManager().checkPermission(Maintenance.class, getUserId(), event.getMaintenanceId());
+ }
return event;
}
diff --git a/src/org/traccar/api/resource/MaintenanceResource.java b/src/org/traccar/api/resource/MaintenanceResource.java
new file mode 100644
index 000000000..b3726b429
--- /dev/null
+++ b/src/org/traccar/api/resource/MaintenanceResource.java
@@ -0,0 +1,36 @@
+/*
+ * 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.api.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.model.Maintenance;
+
+@Path("maintenances")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class MaintenanceResource extends ExtendedObjectResource<Maintenance> {
+
+ public MaintenanceResource() {
+ super(Maintenance.class);
+ }
+
+}
diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java
index 9ceb995ef..8ddced5f7 100644
--- a/src/org/traccar/database/CommandsManager.java
+++ b/src/org/traccar/database/CommandsManager.java
@@ -37,8 +37,11 @@ public class CommandsManager extends ExtendedObjectManager<Command> {
private final Map<Long, Queue<Command>> deviceQueues = new ConcurrentHashMap<>();
- public CommandsManager(DataManager dataManager) {
+ private boolean queueing;
+
+ public CommandsManager(DataManager dataManager, boolean queueing) {
super(dataManager, Command.class);
+ this.queueing = queueing;
}
public boolean checkDeviceCommand(long deviceId, long commandId) {
@@ -70,6 +73,8 @@ public class CommandsManager extends ExtendedObjectManager<Command> {
ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId);
if (activeDevice != null) {
activeDevice.sendCommand(command);
+ } else if (!queueing) {
+ throw new RuntimeException("Device is not online");
} else {
getDeviceQueue(deviceId).add(command);
return false;
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index a997a89f6..3c26685bd 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -48,6 +48,7 @@ import org.traccar.model.Driver;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.model.ManagedUser;
import org.traccar.model.Notification;
import org.traccar.model.Permission;
@@ -189,19 +190,19 @@ public class DataManager {
public static String constructPermissionQuery(String action, Class<?> owner, Class<?> property) {
switch (action) {
- case ACTION_SELECT_ALL:
- return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM "
- + getPermissionsTableName(owner, property);
- case ACTION_INSERT:
- return "INSERT INTO " + getPermissionsTableName(owner, property)
- + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:"
- + makeNameId(owner) + ", :" + makeNameId(property) + ")";
- case ACTION_DELETE:
- return "DELETE FROM " + getPermissionsTableName(owner, property)
- + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner)
- + " AND " + makeNameId(property) + " = :" + makeNameId(property);
- default:
- throw new IllegalArgumentException("Unknown action");
+ case ACTION_SELECT_ALL:
+ return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM "
+ + getPermissionsTableName(owner, property);
+ case ACTION_INSERT:
+ return "INSERT INTO " + getPermissionsTableName(owner, property)
+ + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:"
+ + makeNameId(owner) + ", :" + makeNameId(property) + ")";
+ case ACTION_DELETE:
+ return "DELETE FROM " + getPermissionsTableName(owner, property)
+ + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner)
+ + " AND " + makeNameId(property) + " = :" + makeNameId(property);
+ default:
+ throw new IllegalArgumentException("Unknown action");
}
}
@@ -405,6 +406,8 @@ public class DataManager {
return Calendar.class;
case "command":
return Command.class;
+ case "maintenance":
+ return Maintenance.class;
case "notification":
return Notification.class;
default:
diff --git a/src/org/traccar/database/LdapProvider.java b/src/org/traccar/database/LdapProvider.java
index 44dd386ed..eb975ad0f 100644
--- a/src/org/traccar/database/LdapProvider.java
+++ b/src/org/traccar/database/LdapProvider.java
@@ -150,7 +150,7 @@ public class LdapProvider {
user.setEmail(accountName);
}
}
- user.setAdmin(isAdmin(accountName));
+ user.setAdministrator(isAdmin(accountName));
} catch (NamingException e) {
user.setLogin(accountName);
user.setName(accountName);
diff --git a/src/org/traccar/database/MaintenancesManager.java b/src/org/traccar/database/MaintenancesManager.java
new file mode 100644
index 000000000..4e266cb78
--- /dev/null
+++ b/src/org/traccar/database/MaintenancesManager.java
@@ -0,0 +1,27 @@
+/*
+ * 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.database;
+
+import org.traccar.model.Maintenance;
+
+public class MaintenancesManager extends ExtendedObjectManager<Maintenance> {
+
+ public MaintenancesManager(DataManager dataManager) {
+ super(dataManager, Maintenance.class);
+ }
+
+}
diff --git a/src/org/traccar/database/NotificationManager.java b/src/org/traccar/database/NotificationManager.java
index 1c59a8666..3bc048356 100644
--- a/src/org/traccar/database/NotificationManager.java
+++ b/src/org/traccar/database/NotificationManager.java
@@ -78,8 +78,10 @@ public class NotificationManager extends ExtendedObjectManager<Notification> {
usersToForward = new HashSet<>();
}
for (long userId : users) {
- if (event.getGeofenceId() == 0 || Context.getGeofenceManager() != null
- && Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId())) {
+ if ((event.getGeofenceId() == 0
+ || Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId()))
+ && (event.getMaintenanceId() == 0
+ || Context.getMaintenancesManager().checkItemPermission(userId, event.getMaintenanceId()))) {
if (usersToForward != null) {
usersToForward.add(userId);
}
diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java
index 3ae5961ce..1c19f2374 100644
--- a/src/org/traccar/database/PermissionsManager.java
+++ b/src/org/traccar/database/PermissionsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2018 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.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.model.ManagedUser;
import org.traccar.model.Notification;
import org.traccar.model.Permission;
@@ -155,7 +156,7 @@ public class PermissionsManager {
public boolean getUserAdmin(long userId) {
User user = getUser(userId);
- return user != null && user.getAdmin();
+ return user != null && user.getAdministrator();
}
public void checkAdmin(long userId) throws SecurityException {
@@ -257,7 +258,7 @@ public class PermissionsManager {
}
public void checkUserUpdate(long userId, User before, User after) throws SecurityException {
- if (before.getAdmin() != after.getAdmin()
+ if (before.getAdministrator() != after.getAdministrator()
|| before.getDeviceLimit() != after.getDeviceLimit()
|| before.getUserLimit() != after.getUserLimit()) {
checkAdmin(userId);
@@ -337,6 +338,8 @@ public class PermissionsManager {
manager = Context.getCalendarManager();
} else if (object.equals(Command.class)) {
manager = Context.getCommandsManager();
+ } else if (object.equals(Maintenance.class)) {
+ manager = Context.getMaintenancesManager();
} else if (object.equals(Notification.class)) {
manager = Context.getNotificationManager();
} else {
@@ -362,6 +365,7 @@ public class PermissionsManager {
Context.getDriversManager().refreshUserItems();
Context.getAttributesManager().refreshUserItems();
Context.getCommandsManager().refreshUserItems();
+ Context.getMaintenancesManager().refreshUserItems();
if (Context.getNotificationManager() != null) {
Context.getNotificationManager().refreshUserItems();
}
@@ -374,6 +378,7 @@ public class PermissionsManager {
Context.getDriversManager().refreshExtendedPermissions();
Context.getAttributesManager().refreshExtendedPermissions();
Context.getCommandsManager().refreshExtendedPermissions();
+ Context.getMaintenancesManager().refreshExtendedPermissions();
}
public void refreshPermissions(Permission permission) {
@@ -394,6 +399,8 @@ public class PermissionsManager {
Context.getCalendarManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Command.class)) {
Context.getCommandsManager().refreshUserItems();
+ } else if (permission.getPropertyClass().equals(Maintenance.class)) {
+ Context.getMaintenancesManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Notification.class)
&& Context.getNotificationManager() != null) {
Context.getNotificationManager().refreshUserItems();
@@ -407,6 +414,8 @@ public class PermissionsManager {
Context.getAttributesManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Command.class)) {
Context.getCommandsManager().refreshExtendedPermissions();
+ } else if (permission.getPropertyClass().equals(Maintenance.class)) {
+ Context.getMaintenancesManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Notification.class)
&& Context.getNotificationManager() != null) {
Context.getNotificationManager().refreshExtendedPermissions();
diff --git a/src/org/traccar/events/MaintenanceEventHandler.java b/src/org/traccar/events/MaintenanceEventHandler.java
index 86abf7c17..4a6122826 100644
--- a/src/org/traccar/events/MaintenanceEventHandler.java
+++ b/src/org/traccar/events/MaintenanceEventHandler.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -16,54 +16,47 @@
*/
package org.traccar.events;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import org.traccar.BaseEventHandler;
import org.traccar.Context;
-import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Maintenance;
import org.traccar.model.Position;
public class MaintenanceEventHandler extends BaseEventHandler {
- public static final String ATTRIBUTE_MAINTENANCE_START = "maintenance.start";
- public static final String ATTRIBUTE_MAINTENANCE_INTERVAL = "maintenance.interval";
-
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- Device device = Context.getIdentityManager().getById(position.getDeviceId());
- if (device == null || !Context.getIdentityManager().isLatestPosition(position)) {
- return null;
- }
-
- double maintenanceInterval = Context.getDeviceManager()
- .lookupAttributeDouble(device.getId(), ATTRIBUTE_MAINTENANCE_INTERVAL, 0, false);
- if (maintenanceInterval == 0) {
+ if (Context.getIdentityManager().getById(position.getDeviceId()) == null
+ || !Context.getIdentityManager().isLatestPosition(position)) {
return null;
}
- double maintenanceStart = Context.getDeviceManager()
- .lookupAttributeDouble(device.getId(), ATTRIBUTE_MAINTENANCE_START, 0, false);
-
- double oldTotalDistance = 0.0;
- double newTotalDistance = 0.0;
Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId());
- if (lastPosition != null) {
- oldTotalDistance = lastPosition.getDouble(Position.KEY_TOTAL_DISTANCE);
+ if (lastPosition == null) {
+ return null;
}
- newTotalDistance = position.getDouble(Position.KEY_TOTAL_DISTANCE);
-
- oldTotalDistance -= maintenanceStart;
- newTotalDistance -= maintenanceStart;
- if ((long) (oldTotalDistance / maintenanceInterval) < (long) (newTotalDistance / maintenanceInterval)) {
- Event event = new Event(Event.TYPE_MAINTENANCE, position.getDeviceId(), position.getId());
- event.set(Position.KEY_TOTAL_DISTANCE, newTotalDistance);
- return Collections.singletonMap(event, position);
+ Map<Event, Position> events = new HashMap<>();
+ for (long maintenanceId : Context.getMaintenancesManager().getAllDeviceItems(position.getDeviceId())) {
+ Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId);
+ if (maintenance.getPeriod() != 0) {
+ double oldValue = lastPosition.getDouble(maintenance.getType());
+ double newValue = position.getDouble(maintenance.getType());
+ if (oldValue != 0.0 && newValue != 0.0
+ && (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod())
+ < (long) ((newValue - maintenance.getStart()) / maintenance.getPeriod())) {
+ Event event = new Event(Event.TYPE_MAINTENANCE, position.getDeviceId(), position.getId());
+ event.setMaintenanceId(maintenanceId);
+ event.set(maintenance.getType(), newValue);
+ events.put(event, position);
+ }
+ }
}
- return null;
+ return events;
}
}
diff --git a/src/org/traccar/geocoder/GeocodeXyzGeocoder.java b/src/org/traccar/geocoder/GeocodeXyzGeocoder.java
new file mode 100644
index 000000000..aca360c3d
--- /dev/null
+++ b/src/org/traccar/geocoder/GeocodeXyzGeocoder.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class GeocodeXyzGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String key) {
+ String url = "https://geocode.xyz/%f,%f?geoit=JSON";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ return url;
+ }
+
+ public GeocodeXyzGeocoder(String key, int cacheSize, AddressFormat addressFormat) {
+ super(formatUrl(key), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ Address address = new Address();
+
+ if (json.containsKey("stnumber")) {
+ address.setHouse(json.getString("stnumber"));
+ }
+ if (json.containsKey("staddress")) {
+ address.setStreet(json.getString("staddress"));
+ }
+ if (json.containsKey("city")) {
+ address.setSettlement(json.getString("city"));
+ }
+ if (json.containsKey("region")) {
+ address.setState(json.getString("region"));
+ }
+ if (json.containsKey("prov")) {
+ address.setCountry(json.getString("prov"));
+ }
+ if (json.containsKey("postal")) {
+ address.setPostcode(json.getString("postal"));
+ }
+
+ return address;
+ }
+
+}
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
index 465afeb35..ee7fcc679 100644
--- a/src/org/traccar/model/Event.java
+++ b/src/org/traccar/model/Event.java
@@ -91,4 +91,14 @@ public class Event extends Message {
this.geofenceId = geofenceId;
}
+ private long maintenanceId = 0;
+
+ public long getMaintenanceId() {
+ return maintenanceId;
+ }
+
+ public void setMaintenanceId(long maintenanceId) {
+ this.maintenanceId = maintenanceId;
+ }
+
}
diff --git a/src/org/traccar/model/Maintenance.java b/src/org/traccar/model/Maintenance.java
new file mode 100644
index 000000000..73f67ea96
--- /dev/null
+++ b/src/org/traccar/model/Maintenance.java
@@ -0,0 +1,61 @@
+/*
+ * 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 Maintenance extends ExtendedModel {
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private String type;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ private double start;
+
+ public double getStart() {
+ return start;
+ }
+
+ public void setStart(double start) {
+ this.start = start;
+ }
+
+ private double period;
+
+ public double getPeriod() {
+ return period;
+ }
+
+ public void setPeriod(double period) {
+ this.period = period;
+ }
+
+}
diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java
index fca0f16e3..b0e08244c 100644
--- a/src/org/traccar/model/Position.java
+++ b/src/org/traccar/model/Position.java
@@ -39,6 +39,7 @@ public class Position extends Message {
public static final String KEY_ODOMETER_TRIP = "tripOdometer"; // meters
public static final String KEY_HOURS = "hours";
public static final String KEY_STEPS = "steps";
+ public static final String KEY_HEART_RATE = "heartRate";
public static final String KEY_INPUT = "input";
public static final String KEY_OUTPUT = "output";
public static final String KEY_IMAGE = "image";
diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java
index 1a131a4e8..99e12a072 100644
--- a/src/org/traccar/model/User.java
+++ b/src/org/traccar/model/User.java
@@ -75,14 +75,14 @@ public class User extends ExtendedModel {
this.readonly = readonly;
}
- private boolean admin;
+ private boolean administrator;
- public boolean getAdmin() {
- return admin;
+ public boolean getAdministrator() {
+ return administrator;
}
- public void setAdmin(boolean admin) {
- this.admin = admin;
+ public void setAdministrator(boolean administrator) {
+ this.administrator = administrator;
}
private String map;
diff --git a/src/org/traccar/notification/EventForwarder.java b/src/org/traccar/notification/EventForwarder.java
index b13f8fe43..9d2181e21 100644
--- a/src/org/traccar/notification/EventForwarder.java
+++ b/src/org/traccar/notification/EventForwarder.java
@@ -25,6 +25,7 @@ import org.traccar.helper.Log;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
import org.traccar.model.Position;
import java.nio.charset.StandardCharsets;
@@ -48,6 +49,7 @@ public abstract class EventForwarder {
private static final String KEY_EVENT = "event";
private static final String KEY_GEOFENCE = "geofence";
private static final String KEY_DEVICE = "device";
+ private static final String KEY_MAINTENANCE = "maintenance";
private static final String KEY_USERS = "users";
public final void forwardEvent(Event event, Position position, Set<Long> users) {
@@ -98,6 +100,12 @@ public abstract class EventForwarder {
data.put(KEY_GEOFENCE, geofence);
}
}
+ if (event.getMaintenanceId() != 0) {
+ Maintenance maintenance = Context.getMaintenancesManager().getById(event.getMaintenanceId());
+ if (maintenance != null) {
+ data.put(KEY_MAINTENANCE, maintenance);
+ }
+ }
data.put(KEY_USERS, Context.getUsersManager().getItems(users));
try {
return Context.getObjectMapper().writeValueAsString(data);
diff --git a/src/org/traccar/notification/NotificationFormatter.java b/src/org/traccar/notification/NotificationFormatter.java
index 114825a83..524153721 100644
--- a/src/org/traccar/notification/NotificationFormatter.java
+++ b/src/org/traccar/notification/NotificationFormatter.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 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.
@@ -57,6 +57,9 @@ public final class NotificationFormatter {
if (event.getGeofenceId() != 0) {
velocityContext.put("geofence", Context.getGeofenceManager().getById(event.getGeofenceId()));
}
+ if (event.getMaintenanceId() != 0) {
+ velocityContext.put("maintenance", Context.getMaintenancesManager().getById(event.getMaintenanceId()));
+ }
String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID);
if (driverUniqueId != null) {
velocityContext.put("driver", Context.getDriversManager().getDriverByUniqueId(driverUniqueId));
diff --git a/src/org/traccar/protocol/AquilaProtocolDecoder.java b/src/org/traccar/protocol/AquilaProtocolDecoder.java
index 960139b3f..9963ead34 100644
--- a/src/org/traccar/protocol/AquilaProtocolDecoder.java
+++ b/src/org/traccar/protocol/AquilaProtocolDecoder.java
@@ -17,6 +17,7 @@ package org.traccar.protocol;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.Context;
import org.traccar.DeviceSession;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -242,7 +243,7 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder {
.number("([01]),") // charge
.number("(d+.d+),") // power
.number("(d+.d+),") // battery
- .number("[01],") // emergency
+ .number("([01]),") // emergency
.expression("[CO],") // tamper
.number("(d+),") // rssi
.number("(d+),") // mcc
@@ -269,7 +270,8 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ String id = parser.next();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
if (deviceSession == null) {
return null;
}
@@ -295,6 +297,15 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, parser.nextDouble());
position.set(Position.KEY_BATTERY, parser.nextDouble());
+ if (parser.nextInt() == 1) {
+ position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ if (channel != null) {
+ String password = Context.getIdentityManager().lookupAttributeString(
+ position.getDeviceId(), getProtocolName() + ".language", "aquila123", true);
+ channel.write("#set$" + id + "@" + password + "#EMR_MODE:0*");
+ }
+ }
+
Network network = new Network();
int rssi = parser.nextInt();
diff --git a/src/org/traccar/protocol/AtrackFrameDecoder.java b/src/org/traccar/protocol/AtrackFrameDecoder.java
index ce4a9a65f..224679bde 100644
--- a/src/org/traccar/protocol/AtrackFrameDecoder.java
+++ b/src/org/traccar/protocol/AtrackFrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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 AtrackFrameDecoder extends FrameDecoder {
return buf.readBytes(KEEPALIVE_LENGTH);
}
- } else if (buf.getUnsignedShort(buf.readerIndex()) == 0x4050) {
+ } else if (buf.getUnsignedShort(buf.readerIndex()) == 0x4050 && buf.getByte(buf.readerIndex() + 2) != ',') {
if (buf.readableBytes() > 6) {
int length = buf.getUnsignedShort(buf.readerIndex() + 4) + 4 + 2;
diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java
index 8138f0fcb..b0f094103 100644
--- a/src/org/traccar/protocol/AtrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java
@@ -21,6 +21,7 @@ import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -219,7 +220,8 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
- private Position decodeString(Channel channel, SocketAddress remoteAddress, String sentence) {
+ private Position decodeInfo(Channel channel, SocketAddress remoteAddress, String sentence) {
+
Position position = new Position(getProtocolName());
getLastLocation(position, null);
@@ -258,21 +260,70 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
}
}
- @Override
- protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("@P,")
+ .number("x+,") // checksum
+ .number("d+,") // length
+ .number("d+,") // index
+ .number("(d+),") // imei
+ .number("(dddd)(dd)(dd)") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("d+,") // rtc date and time
+ .number("d+,") // device date and time
+ .number("(-?d+),") // longitude
+ .number("(-?d+),") // latitude
+ .number("(d+),") // course
+ .number("(d+),") // report id
+ .number("(d+.d+),") // odometer
+ .number("(d+),") // hdop
+ .number("(d+),") // inputs
+ .number("(d+),") // speed
+ .number("(d+),") // outputs
+ .number("(d+),") // adc
+ .number("[^,]*,") // driver
+ .number("(d+),") // temp1
+ .number("(d+),") // temp2
+ .any()
+ .compile();
- ChannelBuffer buf = (ChannelBuffer) msg;
+ private Position decodeText(Channel channel, SocketAddress remoteAddress, String sentence) {
- if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) {
- if (channel != null) {
- channel.write(buf, remoteAddress); // keep-alive message
- }
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
return null;
- } else if (buf.getByte(buf.readerIndex()) == '$') {
- return decodeString(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim());
}
+ 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.nextInt() * 0.000001);
+ position.setLatitude(parser.nextInt() * 0.000001);
+ position.setCourse(parser.nextInt());
+
+ position.set(Position.KEY_EVENT, parser.nextInt());
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 100);
+ position.set(Position.KEY_HDOP, parser.nextInt() * 0.1);
+ position.set(Position.KEY_INPUT, parser.nextInt());
+
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+
+ position.set(Position.KEY_OUTPUT, parser.nextInt());
+ position.set(Position.PREFIX_ADC + 1, parser.nextInt());
+ position.set(Position.PREFIX_TEMP + 1, parser.nextInt());
+ position.set(Position.PREFIX_TEMP + 2, parser.nextInt());
+
+ return position;
+ }
+
+ private List<Position> decodeBinary(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
+
buf.skipBytes(2); // prefix
buf.readUnsignedShort(); // checksum
buf.readUnsignedShort(); // length
@@ -360,4 +411,29 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
+ private void sendResponse(Channel channel, SocketAddress remoteAddress) {
+ if (channel != null) {
+ channel.write(ChannelBuffers.wrappedBuffer(DataConverter.parseHex("fe02")), remoteAddress);
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ sendResponse(channel, remoteAddress);
+
+ if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) {
+ return null;
+ } else if (buf.getByte(buf.readerIndex()) == '$') {
+ return decodeInfo(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim());
+ } else if (buf.getByte(buf.readerIndex() + 2) == ',') {
+ return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim());
+ } else {
+ return decodeBinary(channel, remoteAddress, buf);
+ }
+ }
+
}
diff --git a/src/org/traccar/protocol/ContinentalProtocol.java b/src/org/traccar/protocol/ContinentalProtocol.java
index e2b1226cf..5f43a51f7 100644
--- a/src/org/traccar/protocol/ContinentalProtocol.java
+++ b/src/org/traccar/protocol/ContinentalProtocol.java
@@ -34,7 +34,7 @@ public class ContinentalProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2));
+ pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0));
pipeline.addLast("objectDecoder", new ContinentalProtocolDecoder(ContinentalProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/ContinentalProtocolDecoder.java b/src/org/traccar/protocol/ContinentalProtocolDecoder.java
index 726d9e16b..37913b657 100644
--- a/src/org/traccar/protocol/ContinentalProtocolDecoder.java
+++ b/src/org/traccar/protocol/ContinentalProtocolDecoder.java
@@ -16,10 +16,10 @@
package org.traccar.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
@@ -37,22 +37,6 @@ public class ContinentalProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_ACK = 0x06;
public static final int MSG_NACK = 0x15;
- private void sendResponse(Channel channel, long serialNumber) {
- if (channel != null) {
- ChannelBuffer response = ChannelBuffers.dynamicBuffer();
-
- response.writeByte('S');
- response.writeByte('V');
- response.writeShort(2 + 2 + 1 + 4 + 2); // length
- response.writeByte(1); // version
- response.writeInt((int) serialNumber);
- response.writeByte(0); // product
- response.writeByte(MSG_ACK);
-
- channel.write(response);
- }
- }
-
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -69,8 +53,6 @@ public class ContinentalProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- sendResponse(channel, serialNumber);
-
buf.readUnsignedByte(); // product
int type = buf.readUnsignedByte();
@@ -96,13 +78,25 @@ public class ContinentalProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000L));
position.set(Position.KEY_EVENT, buf.readUnsignedShort());
- position.set(Position.KEY_INPUT, buf.readUnsignedShort());
+
+ int input = buf.readUnsignedShort();
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
+ position.set(Position.KEY_INPUT, input);
+
position.set(Position.KEY_OUTPUT, buf.readUnsignedShort());
position.set(Position.KEY_BATTERY, buf.readUnsignedByte());
position.set(Position.KEY_DEVICE_TEMP, buf.readByte());
buf.readUnsignedShort(); // reserved
+ if (buf.readableBytes() > 4) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ }
+
+ if (buf.readableBytes() > 4) {
+ position.set(Position.KEY_HOURS, buf.readUnsignedInt());
+ }
+
return position;
}
diff --git a/src/org/traccar/protocol/EelinkProtocolDecoder.java b/src/org/traccar/protocol/EelinkProtocolDecoder.java
index 0ed81c925..0fda6fb74 100644
--- a/src/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2018 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.
@@ -170,7 +170,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private Position decodeNew(DeviceSession deviceSession, ChannelBuffer buf, int index) {
+ private Position decodeNew(DeviceSession deviceSession, ChannelBuffer buf, int type, int index) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -218,43 +218,59 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
buf.skipBytes(7); // bss2
}
- if (buf.readableBytes() >= 2) {
+ if (type == MSG_WARNING) {
+
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+
+ } else if (type == MSG_REPORT) {
+
+ buf.readUnsignedByte(); // report type
+
+ }
+
+ if (type == MSG_NORMAL || type == MSG_WARNING || type == MSG_REPORT) {
+
int status = buf.readUnsignedShort();
position.setValid(BitUtil.check(status, 0));
if (BitUtil.check(status, 1)) {
position.set(Position.KEY_IGNITION, BitUtil.check(status, 2));
}
position.set(Position.KEY_STATUS, status);
- }
- if (buf.readableBytes() >= 2) {
- position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001);
}
- if (buf.readableBytes() >= 4) {
- position.set(Position.PREFIX_ADC + 0, buf.readUnsignedShort());
- position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
- }
+ if (type == MSG_NORMAL) {
- if (buf.readableBytes() >= 4) {
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
- }
+ if (buf.readableBytes() >= 2) {
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001);
+ }
- if (buf.readableBytes() >= 4) {
- buf.readUnsignedShort(); // gsm counter
- buf.readUnsignedShort(); // gps counter
- }
+ if (buf.readableBytes() >= 4) {
+ position.set(Position.PREFIX_ADC + 0, buf.readUnsignedShort());
+ position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
+ }
- if (buf.readableBytes() >= 4) {
- position.set(Position.KEY_STEPS, buf.readUnsignedShort());
- buf.readUnsignedShort(); // walking time
- }
+ if (buf.readableBytes() >= 4) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ }
+
+ if (buf.readableBytes() >= 4) {
+ buf.readUnsignedShort(); // gsm counter
+ buf.readUnsignedShort(); // gps counter
+ }
+
+ if (buf.readableBytes() >= 4) {
+ position.set(Position.KEY_STEPS, buf.readUnsignedShort());
+ buf.readUnsignedShort(); // walking time
+ }
+
+ if (buf.readableBytes() >= 12) {
+ position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0);
+ position.set("humidity", buf.readUnsignedShort() * 0.1);
+ position.set("illuminance", buf.readUnsignedInt() / 256.0);
+ position.set("co2", buf.readUnsignedInt());
+ }
- if (buf.readableBytes() >= 12) {
- position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0);
- position.set("humidity", buf.readUnsignedShort() * 0.1);
- position.set("illuminance", buf.readUnsignedInt() / 256.0);
- position.set("co2", buf.readUnsignedInt());
}
return position;
@@ -355,7 +371,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
} else if (type >= MSG_NORMAL && type <= MSG_OBD_CODE) {
- return decodeNew(deviceSession, buf, index);
+ return decodeNew(deviceSession, buf, type, index);
} else if (type == MSG_HEARTBEAT && buf.readableBytes() >= 2) {
diff --git a/src/org/traccar/protocol/EskyProtocolDecoder.java b/src/org/traccar/protocol/EskyProtocolDecoder.java
index 60ef4f846..bf790541b 100644
--- a/src/org/traccar/protocol/EskyProtocolDecoder.java
+++ b/src/org/traccar/protocol/EskyProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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,16 +37,18 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder {
.number("d+;") // index
.number("(d+);") // imei
.text("R;") // data type
- .number("(d+)").text("+") // satellites
+ .number("(d+)[+;]") // satellites
.number("(dd)(dd)(dd)") // date
- .number("(dd)(dd)(dd)").text("+") // time
- .number("(-?d+.d+)").text("+") // latitude
- .number("(-?d+.d+)").text("+") // longitude
- .number("(d+.d+)").text("+") // speed
- .number("(d+)").text("+") // course
- .text("0x").number("(d+)").text("+") // input
- .number("(d+)").text("+") // message type
- .number("(d+)").text("+") // odometer
+ .number("(dd)(dd)(dd)[+;]") // time
+ .number("(-?d+.d+)[+;]") // latitude
+ .number("(-?d+.d+)[+;]") // longitude
+ .number("(d+.d+)[+;]") // speed
+ .number("(d+)[+;]") // course
+ .groupBegin()
+ .text("0x").number("(d+)[+;]") // input
+ .number("(d+)[+;]") // message type
+ .number("(d+)[+;]") // odometer
+ .groupEnd("?")
.number("(d+)") // voltage
.any()
.compile();
@@ -77,10 +79,13 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(UnitsConverter.knotsFromMps(parser.nextDouble()));
position.setCourse(parser.nextDouble());
- position.set(Position.KEY_INPUT, parser.nextHexInt());
- position.set(Position.KEY_EVENT, parser.nextInt());
- position.set(Position.KEY_ODOMETER, parser.nextInt());
- position.set(Position.KEY_POWER, parser.nextInt());
+ if (parser.hasNext(3)) {
+ position.set(Position.KEY_INPUT, parser.nextHexInt());
+ position.set(Position.KEY_EVENT, parser.nextInt());
+ position.set(Position.KEY_ODOMETER, parser.nextInt());
+ }
+
+ position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001);
return position;
}
diff --git a/src/org/traccar/protocol/GatorProtocolDecoder.java b/src/org/traccar/protocol/GatorProtocolDecoder.java
index 9cd746f51..b38214457 100644
--- a/src/org/traccar/protocol/GatorProtocolDecoder.java
+++ b/src/org/traccar/protocol/GatorProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2018 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.
@@ -56,7 +56,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
return String.format("%02d%02d%02d%02d%02d", d1, d2, d3, d4, d5);
}
- private void sendResponse(Channel channel, byte calibration) {
+ private void sendResponse(Channel channel, SocketAddress remoteAddress, byte calibration) {
if (channel != null) {
ChannelBuffer response = ChannelBuffers.dynamicBuffer();
response.writeByte(0x24); response.writeByte(0x24); // header
@@ -67,7 +67,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
response.writeByte(0); // slave order
response.writeByte(1); // calibration
response.writeByte(0x0D);
- channel.write(response);
+ channel.write(response, remoteAddress);
}
}
@@ -85,7 +85,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(), buf.readUnsignedByte(),
buf.readUnsignedByte(), buf.readUnsignedByte());
- sendResponse(channel, buf.getByte(buf.writerIndex() - 2));
+ sendResponse(channel, remoteAddress, buf.getByte(buf.writerIndex() - 2));
if (type == MSG_POSITION_DATA || type == MSG_ROLLCALL_RESPONSE
|| type == MSG_ALARM_DATA || type == MSG_BLIND_AREA) {
diff --git a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
index ff300d429..598cee814 100644
--- a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
@@ -828,6 +828,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
+ position.set(Position.KEY_IGNITION, sentence.contains("IGN"));
position.set(Position.KEY_HOURS, parser.next());
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
@@ -918,6 +919,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_MOTION, reportType == 1);
} else if (type.equals("SOS")) {
position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ } else if (type.equals("DIS")) {
+ position.set(Position.PREFIX_IN + reportType / 10, reportType % 10 == 1);
+ } else if (type.equals("IGL")) {
+ position.set(Position.KEY_IGNITION, reportType % 10 == 0);
}
decodeLocation(position, parser);
diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java
index 9764adf04..54671bdbf 100644
--- a/src/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/org/traccar/protocol/H02ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2018 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 H02ProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN = new PatternBuilder()
.text("*")
.expression("..,") // manufacturer
- .number("(d+),") // imei
+ .number("(d+)?,") // imei
.groupBegin()
.text("VP1,")
.or()
diff --git a/src/org/traccar/protocol/L100FrameDecoder.java b/src/org/traccar/protocol/L100FrameDecoder.java
index a597cbd7d..98c2f9768 100644
--- a/src/org/traccar/protocol/L100FrameDecoder.java
+++ b/src/org/traccar/protocol/L100FrameDecoder.java
@@ -41,7 +41,10 @@ public class L100FrameDecoder extends FrameDecoder {
index += 2; // checksum
if (buf.readableBytes() >= index - buf.readerIndex()) {
- return buf.readBytes(index - buf.readerIndex());
+ buf.skipBytes(2); // header
+ ChannelBuffer frame = buf.readBytes(index - buf.readerIndex() - 2);
+ buf.skipBytes(2); // footer
+ return frame;
}
return null;
diff --git a/src/org/traccar/protocol/L100Protocol.java b/src/org/traccar/protocol/L100Protocol.java
index 2bcef4caa..245f073fb 100644
--- a/src/org/traccar/protocol/L100Protocol.java
+++ b/src/org/traccar/protocol/L100Protocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 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,6 +17,8 @@ package org.traccar.protocol;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.string.StringDecoder;
+import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
@@ -34,6 +36,8 @@ public class L100Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new L100FrameDecoder());
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new L100ProtocolDecoder(L100Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/L100ProtocolDecoder.java b/src/org/traccar/protocol/L100ProtocolDecoder.java
index de966d7af..1fe18ff5e 100644
--- a/src/org/traccar/protocol/L100ProtocolDecoder.java
+++ b/src/org/traccar/protocol/L100ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 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 org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
@@ -27,7 +26,6 @@ import org.traccar.model.Network;
import org.traccar.model.Position;
import java.net.SocketAddress;
-import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
public class L100ProtocolDecoder extends BaseProtocolDecoder {
@@ -43,9 +41,9 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
.number("(dd)(dd)(dd)") // time (hhmmss.sss)
.number(".(ddd)").optional()
.expression(",([AV]),") // validity
- .number("(dd)(dd.d+),") // latitude
+ .number("(d+)(dd.d+),") // latitude
.expression("([NS]),")
- .number("(ddd)(dd.d+),") // longitude
+ .number("(d+)(dd.d+),") // longitude
.expression("([EW]),")
.number("(d+.?d*)?,") // speed
.number("(d+.?d*)?,") // course
@@ -59,7 +57,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
.number("(d+.d+),") // odometer
.number("(d+.d+),") // temperature
.number("(d+.d+),") // battery
- .number("(d+),") // gsm
+ .number("(d+),") // rssi
.number("(d+),") // mcc
.number("(d+),") // mnc
.number("(x+),") // lac
@@ -71,12 +69,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- ChannelBuffer buf = (ChannelBuffer) msg;
-
- buf.readUnsignedByte(); // start marker
- buf.readUnsignedByte(); // type
-
- String sentence = buf.readBytes(buf.readableBytes() - 2).toString(StandardCharsets.US_ASCII);
+ String sentence = (String) msg;
Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
@@ -92,7 +85,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
DateBuilder dateBuilder = new DateBuilder()
- .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt(0));
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextCoordinate());
@@ -100,18 +93,20 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(parser.nextDouble(0));
position.setCourse(parser.nextDouble(0));
- dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setTime(dateBuilder.getDate());
position.set(Position.KEY_STATUS, parser.next());
position.set(Position.PREFIX_ADC + 1, parser.next());
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0));
- position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0));
- position.set(Position.KEY_BATTERY, parser.nextDouble(0));
-
- int rssi = parser.nextInt(0);
- position.setNetwork(new Network(CellTower.from(
- parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0), rssi)));
+ position.set(Position.KEY_ODOMETER, parser.nextDouble());
+ position.set(Position.PREFIX_TEMP + 1, parser.nextDouble());
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+
+ int rssi = parser.nextInt();
+ if (rssi > 0) {
+ position.setNetwork(new Network(CellTower.from(
+ parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi)));
+ }
return position;
}
diff --git a/src/org/traccar/protocol/Pt502Protocol.java b/src/org/traccar/protocol/Pt502Protocol.java
index ba820a6a1..f7d0d04a2 100644
--- a/src/org/traccar/protocol/Pt502Protocol.java
+++ b/src/org/traccar/protocol/Pt502Protocol.java
@@ -17,7 +17,6 @@ package org.traccar.protocol;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
diff --git a/src/org/traccar/protocol/Pt60ProtocolDecoder.java b/src/org/traccar/protocol/Pt60ProtocolDecoder.java
index c87c22c5f..26f07a0a9 100644
--- a/src/org/traccar/protocol/Pt60ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Pt60ProtocolDecoder.java
@@ -34,16 +34,19 @@ public class Pt60ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
+ public static final int MSG_TRACK = 6;
+ public static final int MSG_STEP_COUNT = 13;
+ public static final int MSG_HEART_RATE = 14;
+
private static final Pattern PATTERN = new PatternBuilder()
.text("@G#@,") // header
.number("Vdd,") // protocol version
- .number("d,") // type
+ .number("(d+),") // type
.number("(d+),") // imei
.number("(d+),") // imsi
.number("(dddd)(dd)(dd)") // date (yyyymmdd)
.number("(dd)(dd)(dd),") // time (hhmmss)
- .number("(-?d+.d+);") // latitude
- .number("(-?d+.d+),") // longitude
+ .expression("(.*)") // data
.compile();
private void sendResponse(Channel channel) {
@@ -64,6 +67,12 @@ public class Pt60ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ int type = parser.nextInt();
+
+ if (type != MSG_TRACK && type != MSG_STEP_COUNT && type != MSG_HEART_RATE) {
+ return null;
+ }
+
Position position = new Position(getProtocolName());
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next(), parser.next());
@@ -72,10 +81,36 @@ public class Pt60ProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(deviceSession.getDeviceId());
- position.setValid(true);
- position.setTime(parser.nextDateTime());
- position.setLatitude(parser.nextDouble());
- position.setLongitude(parser.nextDouble());
+ position.setDeviceTime(parser.nextDateTime());
+
+ String[] values = parser.next().split(",");
+
+ if (type == MSG_TRACK) {
+
+ position.setValid(true);
+ position.setFixTime(position.getDeviceTime());
+
+ String[] coordinates = values[0].split(";");
+ position.setLatitude(Double.parseDouble(coordinates[0]));
+ position.setLongitude(Double.parseDouble(coordinates[1]));
+
+ } else {
+
+ getLastLocation(position, position.getDeviceTime());
+
+ switch (type) {
+ case MSG_STEP_COUNT:
+ position.set(Position.KEY_STEPS, Integer.parseInt(values[0]));
+ break;
+ case MSG_HEART_RATE:
+ position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[0]));
+ position.set(Position.KEY_BATTERY, Integer.parseInt(values[1]));
+ break;
+ default:
+ break;
+ }
+
+ }
return position;
}
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
index d2069e6c9..3935ebd60 100644
--- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -141,6 +141,16 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
case 80:
position.set("workMode", readValue(buf, length, false));
break;
+ case 129:
+ case 130:
+ case 131:
+ case 132:
+ case 133:
+ case 134:
+ String driver = id == 129 || id == 132 ? "" : position.getString("driver1");
+ position.set("driver" + (id >= 132 ? 2 : 1),
+ driver + buf.readBytes(length).toString(StandardCharsets.US_ASCII).trim());
+ break;
case 179:
position.set(Position.PREFIX_OUT + 1, readValue(buf, length, false) == 1);
break;
diff --git a/src/org/traccar/protocol/Tk103Protocol.java b/src/org/traccar/protocol/Tk103Protocol.java
index 6ef9c0a56..e23982c74 100644
--- a/src/org/traccar/protocol/Tk103Protocol.java
+++ b/src/org/traccar/protocol/Tk103Protocol.java
@@ -47,7 +47,8 @@ public class Tk103Protocol extends BaseProtocol {
Command.TYPE_REBOOT_DEVICE,
Command.TYPE_SET_ODOMETER,
Command.TYPE_ENGINE_STOP,
- Command.TYPE_ENGINE_RESUME);
+ Command.TYPE_ENGINE_RESUME,
+ Command.TYPE_OUTPUT_CONTROL);
}
@Override
diff --git a/src/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/org/traccar/protocol/Tk103ProtocolEncoder.java
index 946f3ad73..3ec562cc3 100644
--- a/src/org/traccar/protocol/Tk103ProtocolEncoder.java
+++ b/src/org/traccar/protocol/Tk103ProtocolEncoder.java
@@ -97,6 +97,8 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder {
return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_OUTPUT_CONTROL:
+ return formatCommand(command, "({%s}AV00{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
default:
Log.warning(new UnsupportedOperationException(command.getType()));
return null;
diff --git a/src/org/traccar/protocol/TotemProtocolDecoder.java b/src/org/traccar/protocol/TotemProtocolDecoder.java
index 5a2c203d2..06a1fbc41 100644
--- a/src/org/traccar/protocol/TotemProtocolDecoder.java
+++ b/src/org/traccar/protocol/TotemProtocolDecoder.java
@@ -245,6 +245,9 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
int io = parser.nextBinInt();
if (pattern == PATTERN1) {
+ if (BitUtil.check(io, 0)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ }
for (int i = 1; i <= 4; i++) {
position.set(Position.PREFIX_IN + i, BitUtil.check(io, 3 + i));
}
@@ -364,7 +367,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
String sentence = (String) msg;
Pattern pattern = PATTERN3;
- if (sentence.indexOf("A") == 6) {
+ if (sentence.charAt(2) == '0') {
pattern = PATTERN4;
} else if (sentence.contains("$GPRMC")) {
pattern = PATTERN1;
diff --git a/src/org/traccar/protocol/WatchProtocolDecoder.java b/src/org/traccar/protocol/WatchProtocolDecoder.java
index b58c3b6a1..f55b6f7be 100644
--- a/src/org/traccar/protocol/WatchProtocolDecoder.java
+++ b/src/org/traccar/protocol/WatchProtocolDecoder.java
@@ -273,7 +273,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
position.set("pressureHigh", values[valueIndex++]);
position.set("pressureLow", values[valueIndex++]);
}
- position.set("pulse", values[valueIndex]);
+ position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[valueIndex]));
return position;
diff --git a/src/org/traccar/reports/Events.java b/src/org/traccar/reports/Events.java
index 7cb6ef6eb..66d9e708d 100644
--- a/src/org/traccar/reports/Events.java
+++ b/src/org/traccar/reports/Events.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -33,6 +33,7 @@ import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.reports.model.DeviceReport;
public final class Events {
@@ -51,7 +52,10 @@ public final class Events {
for (Event event : events) {
if (all || types.contains(event.getType())) {
long geofenceId = event.getGeofenceId();
- if (geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) {
+ long maintenanceId = event.getMaintenanceId();
+ if ((geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId))
+ && (maintenanceId == 0
+ || Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId))) {
result.add(event);
}
}
@@ -67,6 +71,7 @@ public final class Events {
ArrayList<DeviceReport> devicesEvents = new ArrayList<>();
ArrayList<String> sheetNames = new ArrayList<>();
HashMap<Long, String> geofenceNames = new HashMap<>();
+ HashMap<Long, String> maintenanceNames = new HashMap<>();
for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
Context.getPermissionsManager().checkDevice(userId, deviceId);
Collection<Event> events = Context.getDataManager().getEvents(deviceId, from, to);
@@ -75,6 +80,7 @@ public final class Events {
Event event = iterator.next();
if (all || types.contains(event.getType())) {
long geofenceId = event.getGeofenceId();
+ long maintenanceId = event.getMaintenanceId();
if (geofenceId != 0) {
if (Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) {
Geofence geofence = Context.getGeofenceManager().getById(geofenceId);
@@ -84,6 +90,15 @@ public final class Events {
} else {
iterator.remove();
}
+ } else if (maintenanceId != 0) {
+ if (Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId)) {
+ Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId);
+ if (maintenance != null) {
+ maintenanceNames.put(maintenanceId, maintenance.getName());
+ }
+ } else {
+ iterator.remove();
+ }
}
} else {
iterator.remove();
@@ -109,6 +124,7 @@ public final class Events {
jxlsContext.putVar("devices", devicesEvents);
jxlsContext.putVar("sheetNames", sheetNames);
jxlsContext.putVar("geofenceNames", geofenceNames);
+ jxlsContext.putVar("maintenanceNames", maintenanceNames);
jxlsContext.putVar("from", from);
jxlsContext.putVar("to", to);
ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
diff --git a/src/org/traccar/reports/ReportUtils.java b/src/org/traccar/reports/ReportUtils.java
index e04f2f90c..010c88b22 100644
--- a/src/org/traccar/reports/ReportUtils.java
+++ b/src/org/traccar/reports/ReportUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -151,8 +151,10 @@ public final class ReportUtils {
return jxlsContext;
}
- public static void processTemplateWithSheets(InputStream templateStream, OutputStream targetStream,
+ public static void processTemplateWithSheets(
+ InputStream templateStream, OutputStream targetStream,
org.jxls.common.Context jxlsContext) throws IOException {
+
Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream);
List<Area> xlsAreas = new XlsCommentAreaBuilder(transformer).build();
for (Area xlsArea : xlsAreas) {
@@ -166,6 +168,7 @@ public final class ReportUtils {
private static TripReport calculateTrip(
ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
+
Position startTrip = positions.get(startIndex);
Position endTrip = positions.get(endIndex);
@@ -217,10 +220,22 @@ public final class ReportUtils {
trip.setDriverUniqueId(findDriver(startTrip, endTrip));
trip.setDriverName(findDriverName(trip.getDriverUniqueId()));
+ if (!ignoreOdometer
+ && startTrip.getDouble(Position.KEY_ODOMETER) != 0
+ && endTrip.getDouble(Position.KEY_ODOMETER) != 0) {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER));
+ } else {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
return trip;
}
- private static StopReport calculateStop(ArrayList<Position> positions, int startIndex, int endIndex) {
+ private static StopReport calculateStop(
+ ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
+
Position startStop = positions.get(startIndex);
Position endStop = positions.get(endIndex);
@@ -256,16 +271,27 @@ public final class ReportUtils {
}
stop.setEngineHours(engineHours);
+ if (!ignoreOdometer
+ && startStop.getDouble(Position.KEY_ODOMETER) != 0
+ && endStop.getDouble(Position.KEY_ODOMETER) != 0) {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER));
+ } else {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
return stop;
}
- private static <T extends BaseReport> T calculateTripOrStop(ArrayList<Position> positions, int startIndex,
- int endIndex, boolean ignoreOdometer, Class<T> reportClass) {
+ private static <T extends BaseReport> T calculateTripOrStop(
+ ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer, Class<T> reportClass) {
+
if (reportClass.equals(TripReport.class)) {
return (T) calculateTrip(positions, startIndex, endIndex, ignoreOdometer);
} else {
- return (T) calculateStop(positions, startIndex, endIndex);
+ return (T) calculateStop(positions, startIndex, endIndex, ignoreOdometer);
}
}
@@ -289,12 +315,14 @@ public final class ReportUtils {
}
}
- public static <T extends BaseReport> Collection<T> detectTripsAndStops(Collection<Position> positionCollection,
+ public static <T extends BaseReport> Collection<T> detectTripsAndStops(
+ Collection<Position> positionCollection,
TripsConfig tripsConfig, boolean ignoreOdometer, Class<T> reportClass) {
+
Collection<T> result = new ArrayList<>();
ArrayList<Position> positions = new ArrayList<>(positionCollection);
- if (positions != null && !positions.isEmpty()) {
+ if (!positions.isEmpty()) {
boolean trips = reportClass.equals(TripReport.class);
MotionEventHandler motionHandler = new MotionEventHandler(tripsConfig);
DeviceState deviceState = new DeviceState();
@@ -333,6 +361,8 @@ public final class ReportUtils {
ignoreOdometer, reportClass));
}
}
+
return result;
}
+
}
diff --git a/src/org/traccar/reports/Summary.java b/src/org/traccar/reports/Summary.java
index 366e40421..d789a0a9b 100644
--- a/src/org/traccar/reports/Summary.java
+++ b/src/org/traccar/reports/Summary.java
@@ -62,6 +62,17 @@ public final class Summary {
result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer));
result.setAverageSpeed(speedSum / positions.size());
result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition));
+
+ 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));
+ } else {
+ result.setStartOdometer(firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE));
+ result.setEndOdometer(previousPosition.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
}
return result;
}
diff --git a/src/org/traccar/reports/model/BaseReport.java b/src/org/traccar/reports/model/BaseReport.java
index 941e2757f..9f2d1188c 100644
--- a/src/org/traccar/reports/model/BaseReport.java
+++ b/src/org/traccar/reports/model/BaseReport.java
@@ -84,4 +84,23 @@ public class BaseReport {
this.spentFuel = spentFuel;
}
+ private double startOdometer;
+
+ public double getStartOdometer() {
+ return startOdometer;
+ }
+
+ public void setStartOdometer(double startOdometer) {
+ this.startOdometer = startOdometer;
+ }
+ private double endOdometer;
+
+ public double getEndOdometer() {
+ return endOdometer;
+ }
+
+ public void setEndOdometer(double endOdometer) {
+ this.endOdometer = endOdometer;
+ }
+
}
diff --git a/templates/export/events.xlsx b/templates/export/events.xlsx
index f3151d11c..5c5633f3a 100644
--- a/templates/export/events.xlsx
+++ b/templates/export/events.xlsx
Binary files differ
diff --git a/templates/export/stops.xlsx b/templates/export/stops.xlsx
index 0c00b7bff..e4a5248ca 100644
--- a/templates/export/stops.xlsx
+++ b/templates/export/stops.xlsx
Binary files differ
diff --git a/templates/export/summary.xlsx b/templates/export/summary.xlsx
index a71f013a9..94d2b9e79 100644
--- a/templates/export/summary.xlsx
+++ b/templates/export/summary.xlsx
Binary files differ
diff --git a/templates/export/trips.xlsx b/templates/export/trips.xlsx
index c5fa73342..ef803bc4b 100644
--- a/templates/export/trips.xlsx
+++ b/templates/export/trips.xlsx
Binary files differ
diff --git a/templates/mail/maintenance.vm b/templates/mail/maintenance.vm
index 7f69b6c0d..c6973f97a 100644
--- a/templates/mail/maintenance.vm
+++ b/templates/mail/maintenance.vm
@@ -3,7 +3,7 @@
<html>
<body>
Device: $device.name<br>
-Maintenance is required<br>
+Maintenance is required: $maintenance.name<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>
diff --git a/templates/sms/maintenance.vm b/templates/sms/maintenance.vm
index 554b74400..621beae46 100644
--- a/templates/sms/maintenance.vm
+++ b/templates/sms/maintenance.vm
@@ -1 +1 @@
-$device.name maintenance is required at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.serverTime, $locale, $timezone)
+$device.name maintenance $maintenance.name is required at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.serverTime, $locale, $timezone)
diff --git a/test/org/traccar/geocoder/GeocoderTest.java b/test/org/traccar/geocoder/GeocoderTest.java
index 8cf6ac524..12d8b4cd6 100644
--- a/test/org/traccar/geocoder/GeocoderTest.java
+++ b/test/org/traccar/geocoder/GeocoderTest.java
@@ -45,10 +45,8 @@ public class GeocoderTest {
public void onFailure(final Throwable e) {
}
});
- assertEquals("1 Ibn Shaprut St, Jerusalem, Jerusalem District, IL", waitAddress());
- assertEquals("1 Ibn Shaprut St, Jerusalem, Jerusalem District, IL",
- geocoder.getAddress(31.776797, 35.211489, null));
+ assertEquals("1 Ibn Shaprut St, Jerusalem, Jerusalem District, IL", waitAddress());
}
public void testNominatim() throws InterruptedException {
@@ -64,10 +62,8 @@ public class GeocoderTest {
public void onFailure(Throwable e) {
}
});
- assertEquals("35 West 9th Street, NYC, New York, US", waitAddress());
- assertEquals("35 West 9th Street, NYC, New York, US",
- geocoder.getAddress(40.7337807, -73.9974401, null));
+ assertEquals("35 West 9th Street, NYC, New York, US", waitAddress());
}
public void testGisgraphy() throws InterruptedException {
@@ -83,9 +79,8 @@ public class GeocoderTest {
public void onFailure(Throwable e) {
}
});
- assertEquals("Rue du Jardinet, Paris, Île-de-France, FR", waitAddress());
- assertEquals("Rue du Jardinet, Paris, Île-de-France, FR", geocoder.getAddress(48.8530000, 2.3400000, null));
+ assertEquals("Rue du Jardinet, Paris, Île-de-France, FR", waitAddress());
}
public void testOpenCage() throws InterruptedException {
@@ -102,9 +97,8 @@ public class GeocoderTest {
public void onFailure(Throwable e) {
}
});
- assertEquals("Charleston Road, California, US", waitAddress());
- assertEquals("Charleston Road, California, US", geocoder.getAddress(34.116302, -118.051519, null));
+ assertEquals("Charleston Road, California, US", waitAddress());
}
public void testGeocodeFarm() throws InterruptedException {
@@ -120,10 +114,25 @@ public class GeocoderTest {
public void onFailure(Throwable e) {
}
});
+
assertEquals("Estrella Avenue, Arcadia, California, United States", waitAddress());
+ }
+
+ public void testGeocodeXyz() throws InterruptedException {
+ Geocoder geocoder = new GeocodeXyzGeocoder(null, 0, new AddressFormat());
+
+ geocoder.getAddress(34.116302, -118.051519, new Geocoder.ReverseGeocoderCallback() {
+ @Override
+ public void onSuccess(String address) {
+ setAddress(address);
+ }
+
+ @Override
+ public void onFailure(Throwable e) {
+ }
+ });
- assertEquals("Estrella Avenue, Arcadia, California, United States",
- geocoder.getAddress(34.116302, -118.051519, null));
+ assertEquals("605 ESTRELLA AVE, ARCADIA, California United States of America, US", waitAddress());
}
}
diff --git a/test/org/traccar/protocol/AquilaProtocolDecoderTest.java b/test/org/traccar/protocol/AquilaProtocolDecoderTest.java
index 8984cfcb3..d14f00ff1 100644
--- a/test/org/traccar/protocol/AquilaProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/AquilaProtocolDecoderTest.java
@@ -57,6 +57,9 @@ public class AquilaProtocolDecoderTest extends ProtocolTest {
AquilaProtocolDecoder decoder = new AquilaProtocolDecoder(new AquilaProtocol());
verifyPosition(decoder, text(
+ "$Header,iTriangle,1_37T02B0164MAIS_2,NR,1,L,864495034490141,KA01I2000,1,19042018,102926,22.846401,N,75.948952,E,0.0,311,5,578.0,3.80,3.67,AirTel,0,1,12.5,4.3,1,C,14,404,93,0456,16db,29,ebd8,0458,28,3843,18ab,25,072e,18ab,22,35da,0458,0000,00,031181,0.0,0.0,0,()*34"));
+
+ verifyPosition(decoder, text(
"$Header,nliven,1_37T02B0164MAIS,BR,6,L,861693034634154,KA01I2000,1,09112017,160702,12.976593,N,77.549782,E,25.1,344,15,911.0,1.04,0.68,Airtel,1,1,11.8,3.8,1,C,24,404,45,61b4,9ad9,31,9adb,61b4,35,ffff,0000,33,ffff,0000,31,ffff,0000,0001,00,000014,0.0,0.1,4,()*1E"));
verifyPosition(decoder, text(
diff --git a/test/org/traccar/protocol/AtrackFrameDecoderTest.java b/test/org/traccar/protocol/AtrackFrameDecoderTest.java
index 9db4fd052..52ac18026 100644
--- a/test/org/traccar/protocol/AtrackFrameDecoderTest.java
+++ b/test/org/traccar/protocol/AtrackFrameDecoderTest.java
@@ -13,6 +13,10 @@ public class AtrackFrameDecoderTest extends ProtocolTest {
AtrackFrameDecoder decoder = new AtrackFrameDecoder();
assertEquals(
+ binary("40502c373542332c3132302c37393737392c3335383930313034383039313535342c32303138303431323134323531342c32303138303431323134323531342c32303138303431333030303635352c31363432333338392c34383137383730302c3130382c322c362e352c392c302c302c302c302c302c323030302c323030302c1a0d0a"),
+ decoder.decode(null, null, binary("40502c373542332c3132302c37393737392c3335383930313034383039313535342c32303138303431323134323531342c32303138303431323134323531342c32303138303431333030303635352c31363432333338392c34383137383730302c3130382c322c362e352c392c302c302c302c302c302c323030302c323030302c1a0d0a")));
+
+ assertEquals(
binary("244F4B0D0A"),
decoder.decode(null, null, binary("244F4B0D0A")));
diff --git a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java
index bd606c320..1fe579c76 100644
--- a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java
@@ -10,6 +10,12 @@ public class AtrackProtocolDecoderTest extends ProtocolTest {
AtrackProtocolDecoder decoder = new AtrackProtocolDecoder(new AtrackProtocol());
+ verifyPosition(decoder, buffer(
+ "@P,1126,121,104547,358901048091554,20180412143513,20180412143514,20180413060000,16423389,48178700,108,2,6.5,9,0,0,0,0,0,2000,2000,\r\n"));
+
+ verifyPosition(decoder, buffer(
+ "@P,434E,124,104655,358901048091554,20180412143706,20180412143706,20180413060107,16423389,48178700,108,121,6.5,10,0,0,0,0,0,2000,2000,\r\n"));
+
verifyPositions(decoder, binary(
"4050b5ed004a2523000310c83713f8c05a88b43e5a88b43f5a88b43f021e0ad5fffdc0a800f3020003059100080000000000000007d007d046554c533a463d3230393120743d3137204e3d3039303100"));
diff --git a/test/org/traccar/protocol/EelinkProtocolDecoderTest.java b/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
index aaf58b438..b6145c183 100644
--- a/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
@@ -14,6 +14,12 @@ public class EelinkProtocolDecoderTest extends ProtocolTest {
"454C0027E753035254407167747167670100180002035254407167747100200205020500010432000086BD"));
verifyPosition(decoder, binary(
+ "676714002414B05AD43A7D03026B92B10C395499FFD7000000000701CC00002495000014203604067B"));
+
+ verifyNotNull(decoder, binary(
+ "676714004F14B0E68CAFE58AA8E68AA5E8ADA621E5B9BFE4B89CE79C81E6B7B1E59CB3E5B882E58D97E5B1B1E58CBAE696B0E8A5BFE8B7AF3138EFBC88E8B79DE5AE87E998B3E5A4A7E58EA63230E7B1B3EFBC89"));
+
+ verifyPosition(decoder, binary(
"676780005a000001000000004c61743a4e33312e38333935352c4c6f6e3a5738322e36313334362c436f757273653a302e30302c53706565643a302e30306b6d2f682c4461746554696d653a323031372d31322d30322031313a32393a3433"));
verifyPosition(decoder, binary(
diff --git a/test/org/traccar/protocol/EgtsProtocolDecoderTest.java b/test/org/traccar/protocol/EgtsProtocolDecoderTest.java
index af69f321e..3639c6416 100644
--- a/test/org/traccar/protocol/EgtsProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/EgtsProtocolDecoderTest.java
@@ -19,6 +19,9 @@ public class EgtsProtocolDecoderTest extends ProtocolTest {
"0100000b002400a0d601f01900030081030000000101011600030000004238363434393530333436343333373600014cdc"));
verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "0100000b002700030e01211800030e8573890100845e980f0202101500f85d980fb37f50aae9653c2b193708317b00000001c51b"));
+
+ verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN,
"0100010b00a308c26401029808c3640171360d000202101800e19a7b0fcfb4c49a0bfdb87a911801b70000000010d90000180400021c0000120300000000101800f39a7b0f2fc9c39a9bf2b87a914001b50000000010da0000180400021c0000120300000000101800fa9a7b0fc663c39a21eeb87a914001b60000000010da0000180400021c0000120300000000101800069b7b0f56d8c29a26ebb87a919600ab0000000010da0000180400021c00001203000000001018000a9b7b0fb2c5c29a19f4b87a915a007d0000000010da0000180400021c0000120300000000101800089b7b0f68ccc29a21eeb87a9164008f0000000010da0000180400021c0000120300000000101800079b7b0fa0d1c29aa4ecb87a918200980000000010da0000180400021c00001203000000001018000b9b7b0f34c4c29ad3f7b87a915a00670000000010da0000180400021c00001203000000001018000f9b7b0f3dbec29aaf0fb97a91c8005e0000000010dc0000180400021c0000120300000000101800199b7b0f42bbc29a0855b97a9178006b0000000010db0000180400021c00001203000000001018001b9b7b0fc8b6c29a3c5db97a916e007e0000000010db0000180400021c00001203000000001018001a9b7b0fc4b9c29a8159b97a916e00750000000010db0000180400021c00001203000000001018001d9b7b0f94aec29a3363b97a916400930000000010db0000180400021c00001203000000001018001c9b7b0fcdb3c29a3760b97a916e008a0000000010db0000180400021c0000120300000000101800209b7b0f28a1c29af263b97a918200ba0000000010db0000180400021c00001203000000001018001f9b7b0f61a6c29af263b97a917800b30000000010db0000180400021c00001203000000001018001e9b7b0f58acc29af263b97a916400a50000000010db0000180400021c0000120300000000101800299b7b0ff26fc29ab561b97a916e00b20000000010d90000180400021c00001203000000001018002d9b7b0fd05bc29a3760b97a916e00bd0000000010d80000180400021c0000120300000000101800359b7b0f4f31c29abe5bb97a916400b50000000010d70000180400021c0000120300000000101800379b7b0f5d28c29abe5bb97a916e00b40000000010d60000180400021c0000120300000000101800369b7b0fd62cc29abe5bb97a916400bd0000000010d60000180400021c00001203000000001018003c9b7b0fca09c29a0358b97a918c00bc0000000010d50000180400021c0000120300000000101800419b7b0f38ebc19a0855b97a916e00b40000000010d60000180400021c0000120300000000101800449b7b0f4edcc19a8a53b97a916400c30000000010d60000180400021c0000120300000000101800469b7b0fded1c19acb52b97a916e00b70000000010d60000180400021c0000120300000000101800649b7b0f7a69c19a154cb97a810000bc0000000010d60000180400021c0000120300000000101800709b7b0fcc5cc19a114fb97a915000970000000010d70000180400021c0000120300000000101800729b7b0fda53c19a8a53b97a91a0007d0000000010d70000180400021c0000120300000000101800749b7b0fa24ec19a3c5db97a91a000650000000010d70000180400021c0000120300000000101800789b7b0fe74ac19aca7eb97a910e015c0000000010d80000180400021c00001203000000001018007f9b7b0f6e46c19a78e0b97a9190015c0000000010d80000180400021c0000120300000000101800869b7b0f3641c19a144eba7a9190015c0000000010d60000180400021c00001203000000001018008d9b7b0ffd3bc19a74b9ba7a9190015c0000000010d40000180400021c0000120300000000101800949b7b0fc536c19a1524bb7a9186015b0000000010d20000180400021c00001203000000001018009b9b7b0fce30c19af78dbb7a919a015c0000000010d00000180400021c0000120300000000101800a29b7b0f552cc19a93fbbb7a9172015d0000000010cd0000180400021c0000120300000000101800b09b7b0f2521c19a6ec0bc7a9186015b0000000010c90000180400021c0000120300000000101800a99b7b0f5e26c19a8759bc7a915e015b0000000010cb0000180400021c0000120300000000101800b79b7b0fa81fc19a1328bd7a9172015b0000000010c70000180400021c0000120300000000101800be9b7b0f6b1dc19ac686bd7a914a015c0000000010c60000180400021c0000120300000000101800c19b7b0fed1bc19ad2a9bd7a912201530000000010c60000180400021c0000120300000000101800c39b7b0f6223c19af4bdbd7a910401420000000010c60000180400021c0000120300000000101800c29b7b0fe91ec19a42b4bd7a910e014c0000000010c60000180400021c0000120300000000101800c59b7b0f502fc19a1acfbd7a91fa00300000000010c60000180400021c0000120300000000101800c49b7b0fdb27c19ae6c6bd7a91fa00390000000010c60000180400021c0000120300000000101800c79b7b0fb83fc19a8ad9bd7a91f000180000000010c60000180400021b0000120300000000101800c69b7b0fc536c19a52d4bd7a91f000250000000010c60000180400021b0000120300000000101800ca9b7b0fc85fc19a81dfbd7a910401030000000010c50000180400021b0000120300000000101800c89b7b0fe74ac19a86dcbd7a91fa000e0000000010c50000180400021b0000120300000000101800d29b7b0f06b7c19afbe3bd7a91a000100000000010c50000180400021c0000120300000000101800d59b7b0ff0c5c19a6beebd7a91b400410000000010c40000180400021c0000120300000000101800d49b7b0ff4c2c19af2e9bd7a91a000310000000010c40000180400021c0000120300000000101800d39b7b0f3ebcc19a79e5bd7a9196001e0000000010c40000180400021c0000120300000000101800d69b7b0f6dc7c19ae0f5bd7a91c800570000000010c40000180400021c000012030000000016b7"));
verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN,
diff --git a/test/org/traccar/protocol/EskyFrameDecoderTest.java b/test/org/traccar/protocol/EskyFrameDecoderTest.java
index 3b16a9051..ed587e4f3 100644
--- a/test/org/traccar/protocol/EskyFrameDecoderTest.java
+++ b/test/org/traccar/protocol/EskyFrameDecoderTest.java
@@ -11,6 +11,10 @@ public class EskyFrameDecoderTest extends ProtocolTest {
EskyFrameDecoder decoder = new EskyFrameDecoder();
verifyFrame(
+ binary("454f3b303b3836313331313030363436313930383b523b363b3138303432303130343735313b322e39373839363b3130312e36353039313b302e37353b3332303b333339383b313b7c"),
+ decoder.decode(null, null, binary("454f3b303b3836313331313030363436313930383b523b363b3138303432303130343735313b322e39373839363b3130312e36353039313b302e37353b3332303b333339383b313b7c")));
+
+ verifyFrame(
binary("454c3b313b3836343930363032393139363632363b3137303832323134333432363b"),
decoder.decode(null, null, binary("454c3b313b3836343930363032393139363632363b3137303832323134333432363b")));
diff --git a/test/org/traccar/protocol/EskyProtocolDecoderTest.java b/test/org/traccar/protocol/EskyProtocolDecoderTest.java
index 5132f42c1..10112f24c 100644
--- a/test/org/traccar/protocol/EskyProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/EskyProtocolDecoderTest.java
@@ -10,6 +10,9 @@ public class EskyProtocolDecoderTest extends ProtocolTest {
EskyProtocolDecoder decoder = new EskyProtocolDecoder(new EskyProtocol());
+ verifyPosition(decoder, text(
+ "EO;0;861311006461908;R;6;180420104751;2.97896;101.65091;0.75;320;3398;1;|"));
+
verifyNull(decoder, text(
"EL;1;864906029196626;170822143426;"));
diff --git a/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
index 56a159768..7d3fe8d53 100644
--- a/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
@@ -10,6 +10,15 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest {
Gl200TextProtocolDecoder decoder = new Gl200TextProtocolDecoder(new Gl200Protocol());
+ verifyPosition(decoder, buffer(
+ "+RESP:GTIGF,270302,867162025085234,,3519,0,0.0,92,111.2,-116.867638,32.450321,20180327070835,0334,0020,2B24,52CC3DE,00,,243.1,20180327070837,2A98$"));
+
+ verifyPosition(decoder, buffer(
+ "+RESP:GTDIS,270302,867162025086950,,,21,1,1,0.0,81,117.8,-116.862025,32.453497,20180309084516,0334,0020,2B24,52CA916,00,1286.2,20180309084517,357E$"));
+
+ verifyPosition(decoder, buffer(
+ "+RESP:GTIGL,270302,867162025085234,,,01,1,1,0.0,92,111.2,-116.867638,32.450321,20180327070838,0334,0020,2B24,52CC3DE,00,243.1,20180327070839,2A9A$"));
+
verifyPositions(decoder, buffer(
"+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$"));
diff --git a/test/org/traccar/protocol/H02ProtocolDecoderTest.java b/test/org/traccar/protocol/H02ProtocolDecoderTest.java
index adbdc0a07..3a758069c 100644
--- a/test/org/traccar/protocol/H02ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/H02ProtocolDecoderTest.java
@@ -15,6 +15,9 @@ public class H02ProtocolDecoderTest extends ProtocolTest {
"*HQ,353505221264507,V2,100220,0,5238.26259,N,00507.33983,E,0.25,0,280917,FFFFFFFF,cc,28, db,d75b#"));
verifyPosition(decoder, buffer(
+ "*HQ,,V1,173212,A,2225.78879,S,02829.19021,E,0.00,0,290418,FFFFFBFF#"));
+
+ verifyPosition(decoder, buffer(
"*HQ,353505221264507,VI1,075146,0,5238.25900,N,00507.33429,E,0.54,0,250917,FFFFFFFF,cc,28, db,d75b#"));
verifyNull(decoder, buffer(
diff --git a/test/org/traccar/protocol/L100FrameDecoderTest.java b/test/org/traccar/protocol/L100FrameDecoderTest.java
index fc6a892dc..7cb385d3e 100644
--- a/test/org/traccar/protocol/L100FrameDecoderTest.java
+++ b/test/org/traccar/protocol/L100FrameDecoderTest.java
@@ -3,8 +3,6 @@ package org.traccar.protocol;
import org.junit.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
-
public class L100FrameDecoderTest extends ProtocolTest {
@Test
@@ -12,12 +10,12 @@ public class L100FrameDecoderTest extends ProtocolTest {
L100FrameDecoder decoder = new L100FrameDecoder();
- assertEquals(
- binary("200141544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c027a"),
+ verifyFrame(
+ binary("41544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c"),
decoder.decode(null, null, binary("200141544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c027a")));
- assertEquals(
- binary("200341544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735244c4f432c436f6e6e61756768742043697263757320c2a0436f6e6e617567687420506c61636520c2a04e65772044656c686920c2a044656c6869c2a0496e6469612c2330313130303130313130313031302c322e332c33352e36372c38302c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c047a"),
+ verifyFrame(
+ binary("41544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735244c4f432c436f6e6e61756768742043697263757320c2a0436f6e6e617567687420506c61636520c2a04e65772044656c686920c2a044656c6869c2a0496e6469612c2330313130303130313130313031302c322e332c33352e36372c38302c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c"),
decoder.decode(null, null, binary("200341544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735244c4f432c436f6e6e61756768742043697263757320c2a0436f6e6e617567687420506c61636520c2a04e65772044656c686920c2a044656c6869c2a0496e6469612c2330313130303130313130313031302c322e332c33352e36372c38302c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c047a")));
}
diff --git a/test/org/traccar/protocol/L100ProtocolDecoderTest.java b/test/org/traccar/protocol/L100ProtocolDecoderTest.java
index 47159debe..04d3f8b5b 100644
--- a/test/org/traccar/protocol/L100ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/L100ProtocolDecoderTest.java
@@ -10,14 +10,20 @@ public class L100ProtocolDecoderTest extends ProtocolTest {
L100ProtocolDecoder decoder = new L100ProtocolDecoder(new L100Protocol());
- verifyPosition(decoder, binary(
- "200141544c3836383030343032363939373235372c244750524d432c3039353534322c412c323833382e303130372c4e2c30373731332e333537392c452c302c39382c3031303631372c2c2c2a30332c2330313131313031313030303030302c302c302c302c302e30312c34352e39342c342e302c32352c3430342c342c38382c3361643541544c0234"));
+ verifyPosition(decoder, text(
+ "ATL867857039216564,$GPRMC,131101,A,2838.010010,N,7713.354980,E,0,0,240418,,,*09,#00011011000000,0,0,0,10.70,24.31,3.8,0,0,0,0,0ATL"));
- verifyPosition(decoder, binary(
- "200141544c3836313639333033353238353235332c244750524d432c3032323034302c412c323935342e303438312c4e2c30373335332e313639342c452c302c3135302c3238303431372c2c2c2a33362c2330313131313031313030303030302c302c302c302c38322e39322c33372e39322c342e302c32332c3430342c37302c3136332c6231373841544c0265"));
+ verifyPosition(decoder, text(
+ "ATL867857039216564,$GPRMC,131033,A,2838.010010,N,7713.354980,E,0,51,240418,,,*3D,#00011011000000,0,0,0,10.70,24.31,3.8,20,404,4,88,cfaaATL"));
- verifyPosition(decoder, binary(
- "200141544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a37352c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c3130302c3030302c3030303030312c303030303041544c027a"));
+ verifyPosition(decoder, text(
+ "ATL868004026997257,$GPRMC,095542,A,2838.0107,N,07713.3579,E,0,98,010617,,,*03,#01111011000000,0,0,0,0.01,45.94,4.0,25,404,4,88,3ad5ATL"));
+
+ verifyPosition(decoder, text(
+ "ATL861693035285253,$GPRMC,022040,A,2954.0481,N,07353.1694,E,0,150,280417,,,*36,#01111011000000,0,0,0,82.92,37.92,4.0,23,404,70,163,b178ATL"));
+
+ verifyPosition(decoder, text(
+ "ATL356895037533745,$GPRMC,111719.000,A,2838.0045,N,07713.3707,E,0.00,,120810,,,A*75,#01100111001010,N.C,N.C,N.C,12345.67,31.4,4.2,21,100,000,000001,00000ATL"));
}
diff --git a/test/org/traccar/protocol/Pt60ProtocolDecoderTest.java b/test/org/traccar/protocol/Pt60ProtocolDecoderTest.java
index 08fe7658e..69d77fe66 100644
--- a/test/org/traccar/protocol/Pt60ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Pt60ProtocolDecoderTest.java
@@ -10,6 +10,12 @@ public class Pt60ProtocolDecoderTest extends ProtocolTest {
Pt60ProtocolDecoder decoder = new Pt60ProtocolDecoder(new Pt60Protocol());
+ verifyAttributes(decoder, text(
+ "@G#@,V01,14,357653051059785,9404223001501310,20180419165604,101,26,"));
+
+ verifyAttributes(decoder, text(
+ "@G#@,V01,13,357653051059785,9404223001501310,20180419112656,1180,"));
+
verifyPosition(decoder, text(
"@G#@,V01,6,111112222233333,8888888888888888,20150312010203,23.2014050;104.235212,"));
diff --git a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
index d62eef4a0..c76247ac1 100644
--- a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
@@ -15,6 +15,9 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest {
"000F313233343536373839303132333435"));
verifyPositions(decoder, false, binary(
+ "00000000000000A708010000016269E7D9A8000A5A0F0A1CBF8F3300880046120000001C0801014F005100550F740073007801790103430000440000426F980B540000000056000045275700000047580000022659000000005D0000000068000003D07100007355870000000288000000008A000045270669584C5241534834336A30304731363538326B3600FFFFFF0000008155412055414430308230303039383236368330303000000000000100008396"));
+
+ verifyPositions(decoder, false, binary(
"0000000000000035080100000161f37c50500020de5ba60ef11450000000000000000006040100b300b400ef000109002000014e0000000000000000010000be52"));
verifyPositions(decoder, false, binary(
diff --git a/test/org/traccar/protocol/Tk103ProtocolEncoderTest.java b/test/org/traccar/protocol/Tk103ProtocolEncoderTest.java
index 565f6bb88..25968a0fe 100644
--- a/test/org/traccar/protocol/Tk103ProtocolEncoderTest.java
+++ b/test/org/traccar/protocol/Tk103ProtocolEncoderTest.java
@@ -9,6 +9,20 @@ import static org.junit.Assert.assertEquals;
public class Tk103ProtocolEncoderTest extends ProtocolTest {
@Test
+ public void testEncodeOutputControl() {
+
+ Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder();
+
+ Command command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_OUTPUT_CONTROL);
+ command.set(Command.KEY_DATA, "1");
+
+ assertEquals("(123456789012345AV001)", encoder.encodeCommand(command));
+
+ }
+
+ @Test
public void testEncodeEngineStop() throws Exception {
Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder();
diff --git a/test/org/traccar/protocol/TotemProtocolDecoderTest.java b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
index 67c75e08d..ae0a240b8 100644
--- a/test/org/traccar/protocol/TotemProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
@@ -11,6 +11,9 @@ public class TotemProtocolDecoderTest extends ProtocolTest {
TotemProtocolDecoder decoder = new TotemProtocolDecoder(new TotemProtocol());
verifyPosition(decoder, text(
+ "$$011602867119025755430|50099800180420045019401400000000000000B8797D110816811201.500002132615.7037S02801.8099E056149"));
+
+ verifyPosition(decoder, text(
"$$0108AB863835028447675|5004C0001710250234064214059828A058AE121010604000.600000320304.7772N10134.8238E11625B"));
verifyPosition(decoder, text(