Пилим сервер GPS мониторинга OpenGTS

Введение


Задача смастерить сервер удаленного GPS/GPRS мониторинга подвижных объектов способный работать с различными моделями GPS трекеров.

Сервер должен:
  • Принимать данные от трекеров: id трекера; время создания пакета данных;
    данные GPS: координаты, скорость, высота, азимут и т.п.;
    данные всяких датчиков: едет/стоит, одометр, кол-во топлива, различные цифровые и аналоговые датчики и т.п.
    Большинство трекеров шлет данные через TCP/UDP на предварительно указанный в настройках трекера IP адрес/порт.
  • Складывать данные в базу данных.
  • Отдавать данные клиентам, чтоб у них на мониторе была карта с мониторимыми объектами.
    Информация о состоянии объектов(стоянка/движение, топливо, датчики и т.п.).
    Возможность получать отчеты по положению/состояниям за промежутки времени.
В данный момент мы пользуемся доморощенным сервером. Не проблема прикрутить к нему разные трекеры, но у него нет клиентской Web морды, только админка базы данных. Клиенты любуются на свои автомобили с помощью отдельной клиентской программы которую не удобно поддерживать.

Как всегда, хочется готового решения за даром.
OpenGTS (автор Martin D. Flynn) единственное opensource решение удовлетворяющее всем требованиям. Существует в двух ипостасях opensource и enterprise за деньги. Сделан из MySQL/MSSQL, Java (ORM базы данных, клиентский/админский веб интерфейс, сервер принимающий данные от трекеров), TomCat.
Полное описание установки/настройки — http://www.opengts.org/OpenGTS_Config.pdf,
форум,
Wiki(требует регистрации на sourceforge).

Здесь было описание установки OpenGTS, но такая длинная статья на хабр не влезла, пришлось установку урезать. Если интересно, пишите в коментах, выложу отдельную статью.

Готовимся пилить

Разобраться в OpenGTS(8Мб исходников — wellcome to Java) без навигации по коду трудно.
Немного помогают javadoc http://www.geotelematic.com/javadocs/index.html Или собрать локально
>ant javadocs
Результат будет лежать в ./OpenGTS_2.2.6/javadocs
Но лучше использовать Eclipse, удобная навигация по коду + отладка.
Здесь http://opengts.org/OpenGTS_Eclipse.pdf рассказано как сделать чтоб OpenGTS собирался и вообще все делал из под Eclipse.
Более простой вариант в Eclipse'е создать проект на основе ANT'овского build.xml, редактировать в Eclipse, собирать в командной строке.
Для отладки запускать что надо(сервер или TomCat) давая Java'e отладочный ключик.
Я вставил ключик в ./OpenGTS_2.2.6/bin/runserver.pl
#---- remote debug;
$Command .= " -Xdebug -Xrunjdwp:transport=dt_socket,address=8998,server=y ";
#вставить перед:
# --- Java Main start-server command


Подробности спросить у Google: eclipse java remote debug.

Пригодится гляделка MySQL базы чтоб понять попали данные в базу или нет.

Мастерим сервер для трекера не поддерживаемого OpenGTS на примере сервера для трекера MoniCar


http://www.monicar.ru/files/OpenGTS_monicar_server.zip там только те файлы которые я менял. Структура директорий в архиве повторяет OpenGTS. Места изменений можно найти поискав комментарии 'imatveev13' и 'ivm'.
Когда я пишу «см. файл» имеется в виду файл из этого архива. Когда я пишу «делаем что то с файлом» имеется в виду файл из установленного OpenGTS.

Сервера поддерживаемых трекеров лежат в ./OpenGTS_2.2.6/src/org/opengts/servers
Там мы наблюдаем:
  • aspicore
  • gtsdmtp — для трекеров поддерживающих протокол OpenDMTP от автора OpenGTS. Таких трекеров не существует, есть ПО для мобильных телефонов с GPS которое превращает телефон в трекер.
  • icare
  • sipgear ZhongShan SIPGEAR Technology Co, Ltd
  • template — заготовка для изготовления сервера
  • template_old — заготовка для изготовления сервера старая
Серверы трекеров OpenGTS не включенные в дистриб.:
Как видите, серверов не густо, автор OpenGTS переместил поддержку популярных трекеров от производителей которые ему не забашляли в enterprise версию. Купленный на e-bay за $100 трекер, скорее всего, в списке отсутствует. А мне был нужен сервер под свой трекер.

Принимаемся мастерить свой сервер. Этот рассказ не подразумевает что читатель, исполняя инструкции, выточит сервер MoniCar. Предполагается что читатель скопирует из архива с сервером директорию monicar куда надо, подправит build.xml и dcservers.xml, соберет, попробует, а рассказом будет пользоваться как пояснением при изготовлении своего сервера.

Копируем директорию template в monicar.
В build.xml добавляем
target name="compile.servers"
target name="monicar"

Как добавлять см. build.xml в выше упомянутом сервере MoniCar

В dcservers.xml добавляем
DCServer name="monicar"
(подробности см. там же)

Во всех файлах новой директории меняем
org.opengts.servers.template;
на
org.opengts.servers.monicar;

Наш новый сервер собирается командой
>ant monicar
и запускается командой
>bin/runserver.pl -s monicar -i
Ключ -i для интерактивного режима, удобно при отладке. Сервер вывалит на консоль кучу отладочной информации и будет ждать данных от трекера, но, пока, сервер не умеет парсить данные. Поэтому останавливаем сервер Ctrl-C и продолжаем пилить.

Поскольку трекер MoniCar шлет данные в виде ASCII строк, в файле Constants.java пишем
public static final boolean ASCII_PACKETS = true;

Как парсить бинарные пакеты данных см. ниже.

Здесь формат данных нашего трекера.
Разбор ASCII данных происходит в TrackClientPacketHandler.java в функции parseInsertRecord_ASCII_1
Трекер MoniCar шлет данные в виде ASCII строки в которой поля разделены символом ';'. Распихиваем поля по элементам массива строк
String fld[] = s.split(";", -1);
Наш трекер, для экономии GPRS трафика, настраивается на посылку только нужных полей. Первое поле в пакете — битовое поле в котором состояние каждого бита говорит включена посылка соответствующего поля или нет. Поскольку не встречал такой фичи у других трекеров, скорее всего, вам это не понадобится, но для протокола
long fieldMask = StringTools.parseLong(fld[0], 0L);
Этот цикл бежит по битам fieldMask и определяет какие поля есть в пакете данных.
for( int i = 0; i < 32; i++){
if ((fieldMask & (1L << i)) != 0){


Получаем уникальный идентификатор(uniqueID) трекера приславшего данные
String modemID = fld[1].toLowerCase();

Под комментарием
/* find Device */
кучка строчек проверяющих наличие трекера с соответствующим уникальным идентификатором в базе данных. Узнает deviceID и какому аккаунту принадлежит трекер. Админ аккаунта должен занести трекер в базу.

Создаем экземпляр класса EventData
EventData.Key evKey = new EventData.Key(accountID, deviceID, 0 , StatusCodes.STATUS_LOCATION);
EventData evdb = evKey.getDBRecord();


Пихаем данные в созданный экземпляр класса в таком духе
evdb.setSpeedKPH(StringTools.parseDouble(fld[fieldCount],0.0));
Второй параметр(0.0) в StringTools.parseDouble(fld[fieldCount],0.0) это значение по умолчанию, на случай если кривую строку подсунули.
Командуем положить данные в базу
device.insertEventData(evdb);

Собираем наш сервер и получаем ошибку в строке
evdb.setFuelTotal(fuelTotal);
говорящую что у класса EventData нет метода setFuelTotal().

Автор OpenGTS заготовил огромную кучу(>100) полей для всевозможных данных от трекера(см. ./OpenGTS_2.2.6/src/org/opengts/db/table/EventData.java). Из жалости к нашему бедному MySQL, по умолчанию(см. StandardFieldInfo), используются только поля имеющие отношение к местоположению машины. Но мы, из принципа, хотим все поля. Где то в недрах конфигурационных файлов, вроде, есть опции подключающие дополнительные поля. Но эта возможность не документирована, а код перед нами.
Открываем EventData.java и учиняем свое описание таблицы
private static final DBField AllFieldInfo[] = {
//сюда копипастим нужные дополнительные поля
}
public static DBFactory getFactory()
{
[...]
//EventData.StandardFieldInfo
EventData.AllFieldInfo

Теперь можно взять скрипт изображающий трекер MoniCar monicar_dummy.pl.txt
и полюбоваться как по Питеру, странным маршрутом, поедая топливо и дрыгая цифровыми входами ездит машина.

Только правильных показаний уровня топлива мы не увидим. OpenGTS подразумевает что трекер присылает данные о количестве топлива в баке, но тупой трекер не знает как вольты на одном из аналоговых входов, к которому подключен датчик топлива, связаны с уровнем топлива. Для преобразования вольт в литры нужна тарировочная таблица. Я(изготовитель трекера) мог бы запихать тарировочную таблицу в трекер, но считаю это не правильным. Эта таблица связана не с трекером, а с датчиком и топливным баком автомобиля. Предположим на одном из автомобилей трекер сломался, заменили на другой. Если таблица в трекере, оператору мониторинга придется новый трекер настраивать: раскопать тарировочную таблицу, залить в трекер, а если датчик не один? Не только топливному датчику, но любому аналоговому, может потребоваться таблица. А если трекер от стороннего производителя и не поддерживает тарировочной таблицы? Тарировочная таблица любого аналогового датчика должна храниться в базе данных и преобразованием должен заниматься сервер.

Логично хранить тарировочную таблицу там же где информацию об автомобиле. В OpenGTS эта информация, вместе с информацией о трекере, хранится в SQL базе в таблице Device. ORM модель таблицы Device в ./OpenGTS_2.2.6/src/org/opengts/db/tables/Device.java
Будем хранить тарировочную таблицу как поле содержащее ASCII строку, содержащую пары [вольты]-[литры], разделенные символом ';'. Т.е. просто добавим поле fuelCalibrationTable типа String, валидатор сочинять лень. Еще добавим поле fuelADCnum где будем хранить к какому аналоговому входу подключен датчик топлива. Getters/setters добавим(будь проклята Java). В ./OpenGTS_2.2.6/src/org/opengts/servers/monicar/TrackClientPacketHandler.java добавим функцию преобразования вольты-литры fuelCalibrated(double x, String calibTabl). Как все добавлять смотри комментарии imatveev13 в соответствующих файлах в
в сервере MoniCar
После сборки OpenGTS команда
>./bin/dbAdmin.pl -tables=ca
приведет базу данных в соответствие с ORM описанием.

Теперь в Веб интерфейсе, в админке устройств надо сделать возможность выбирать к какому входу трекера подключен датчик топлива, и возможность прописывать тарировочную таблицу.
Веб интерфейс живет в TomCat сервлете track.war. Файлы из которых сервлет получается живут в ./OpenGTS_2.2.6/src/org/opengts/war/track. Веб страницу администрации устройств порождает ./OpenGTS_2.2.6/src/org/opengts/war/track/page/DeviceInfo.java. Немного копипаста(см. комментарии imatveev13 в соответствующем файле в в сервере MoniCar) и в Веб форме появляются нужные поля.

Пример как парсить бинарные данные от трекера есть в коде севера meitrack Трекер meitrack шлет комбинированые пакеты в которых бинарные поля: длинна пакета, ID трекера, команада(тип пакета), контрольная сумма. Сами данные в ASCII. Такой пакет считается бинарным. В Constants.java пишем
public static final boolean ASCII_PACKETS = false;
В файле TrackClientPacketHandler.java, в функции getActualPacketLength из бинарной части пакета извлекается длинна пакета и возвращается серверу. Когда сервер до-принимает пакет он вызовет getHandlePacket(byte pktBytes[]) где из бинарной части пакета извлекается ID трекера и вместе с ASCII частью передается в parseInsertRecord_ASCIIdata(String deviceID, String s). Эта функция парсит ASCII данные и помещает в базу.

Ссылки на тему серверов GPS мониторинга

traccar. Open GPS Tracking Server. Java. Сервер трекеров без Веб интерфейса.
android-opengts трамбуют OpenGTS в android.
krastrack. Python, Django. Клон OpenGTS.
traffometer-base-lime. Кажется с этого начинался OpenGTS. Среди авторов есть Martin D. Flynn. Толсто.
GPS-Trace Orange Бесплатный сервис на основе сервера Wialon.
Tags:
gps мониторинг транспорта, gps трекер, gprs, Java

Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.

Similar posts