Pull to refresh

Пилим сервер 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:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.