Введение
Задача смастерить сервер удаленного GPS/GPRS мониторинга подвижных объектов способный работать с различными моделями GPS трекеров.
Сервер должен:
- Принимать данные от трекеров: id трекера; время создания пакета данных;
данные GPS: координаты, скорость, высота, азимут и т.п.;
данные всяких датчиков: едет/стоит, одометр, кол-во топлива, различные цифровые и аналоговые датчики и т.п.
Большинство трекеров шлет данные через TCP/UDP на предварительно указанный в настройках трекера IP адрес/порт. - Складывать данные в базу данных.
- Отдавать данные клиентам, чтоб у них на мониторе была карта с мониторимыми объектами.
Информация о состоянии объектов(стоянка/движение, топливо, датчики и т.п.).
Возможность получать отчеты по положению/состояниям за промежутки времени.
Как всегда, хочется готового решения за даром.
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 — заготовка для изготовления сервера старая
- трекер MoniCar: сервер MoniCar
- MeiTrack trackers: GT30, GT30X, GT60, VT300, VT310.: север meitrack
- Teltonika GH1202: teltonika_gh1202.rar с форума OpenGTS
- Teltonika FM Tracking-devices: TrackClientPacketHandler.java с форума OpenGTS
Принимаемся мастерить свой сервер. Этот рассказ не подразумевает что читатель, исполняя инструкции, выточит сервер 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.