G

gpsdPROXY

Категория проекта: Ожидает модерации
Темы: gpsd gps AIS
+ ещё 5
PHP демон, расширяющий возможности gpsd за счёт указания пользовательской "эпохи" для каждого типа данных

In English

gpsdPROXY daemon License: CC BY-NC-SA 4.0

version 0.8

Весьма удобно обращаться к gpsd из веб-приложений посредством команды ?POLL; в произвольный момент времени, однако есть проблемы:

во-первых, данные AIS недоступны в команде ?POLL;
во-вторых, данные, отличные от тех, что отдаёт приёмник ГПС, могут не попасть в команду ?POLL;

Причина в том, что gpsd собирает данные в течение "эпохи" от одного получения координат приёмником ГПС до другого. Но "эпоха" для данных AIS и приборов гораздо длиннее, и эти данные не попадают в запрос ?POLL;
С деталями и дискуссией по этому поводу можно ознакомиться по следующим ссылкам (англ.):
https://lists.nongnu.org/archive/html/gpsd-users/2020-04/msg00093.html
https://lists.nongnu.org/archive/html/gpsd-users/2021-06/msg00017.html

Однако надо заметить, что gpsdPROXY довольно странная программа, потому что она, в общем, делает ровно то же самое, что и собственно gpsd: собирает данные из потока, агрегирует их и отдаёт структурированные данные по требованию. Разница во времени жизни данных. В gpsdPROXY его можно задавать явным образом для каждого типа данных. Думаю, что такая функциональность должна быть непосредственно в gpsd. Но этого нет.
Зато можно применить gpsdPROXY для сбора данных от источников, в которых нет контроля достоверности данных. Например, от VenusOS, где нет совсем никакого контроля, и от SignalK, где есть хотя бы метка времени. Или просто использовать gpsdPROXY как websocket интерфейс к gpsd.
Дополнительно gpsdPROXY может получать и потом раздавать клиентам информацию "Человек за бортом", а также определять возможность столкновения с целями AIS.

Возможности

Предлагаемый демон собирает данные AIS и всё то, что передаётся gpsd в секции TPV и хранит их в течение указанного пользователем времени. Получить данные можно запросом ?POLL; протокола gpsd.
Таким образом, все данные AIS и данные эхолота и анемометра (и ГПС, конечно) становятся доступными в произвольный момент времени. Дополнительно реализован и синхронная потоковая отдача данных, аналогичная режиму ?WATCH={"enable":true,"json":true} gpsd.

Существует возможность назначить несколько адресов и портов для подключения к gpsdPROXY, например, в сетях ipv4 и ipv6.

Источники данных

Основным источником данных для gpsdPROXY является gpsd, запущенный на той же или другой машине. При использовании gpsd обеспечивается максимальная достоверность данных.
Однако, можно получать данные и из других источников, таких как:

VenusOS

gpsdPROXY может работать под управлением VenusOS по крайней мере начиная с версии v2.80~38, и во всяком случае на Raspberry Pi. Работа в устройствах Victron Energy не проверялась. Однако, gpsdPROXY может получать данные от любого устройства в сети, работающего под управлением VenusOS любой версии.
Для того, чтобы gpsdPROXY мог получать данные, нужно сделать следующие настройки в VenusOS:
В веб-консоли или на экране управления устройства открыть пункты меню Settings -> Services -> MQTT on LAN (SSL) и указать "Включить".

Ограничения
  • в VenusOS нет данных о глубине и нет данных AIS
  • данные, представляемые VenusOS не являются достаточно достоверными и должны использоваться с осторожностью

Signal K

gpsdPROXY может получать данные от сервиса Signal K, работающего на той же машине, или в локальной сети. gpsdPROXY предпримет попытку самостоятельно найти Signal K посредством zeroconf, или обращаясь на стандартный порт. Но лучше сконфигурировать.

Ограничения

На самом деле gpsdPROXY к SignalK должен обращаться только локально. Через сеть -- оно странное.

Обнаружение столкновений

gpsdPROXY определяет возможность столкновений с целями AIS, а зависимости от их и от собственной скорости и указанного времени до события.
collision model

Возможность столкновения вычисляется в соответствии с примитивной моделью движения, учитывающей, фактически, только возможные отклонения от курса. Однако ожидается, что эти вычисления не должны критически загрузить сервер даже при большом количестве целей AIS.
Выходные данные содержат список mmsi и координат потенциально опасных судов. GaladrielMap обозначает такие объекты на карте специальным значком, а у курсора собственного положения рисует стрелочки с направлением на опасный объект.
Для корректной работы надо указать характеристики своего судна в params.php.

Человек за бортом

gpsdPROXY обеспечивает обмен данными "человек за бортом" между поделюченными коиентами. Выходные данные содержат объект GeoJSON с соответствующими точками и линиями.
Кроме того, имеется базовая поддержка сообщений AIS Search and Rescue Transmitter (SART) AIS-MOB и AIS-EPIRB в виде таких данных.

Совместимось

Linux, PHP<8. Кретинские решения, принятые в PHP 8 не позволяют gpsdPROXY работать под PHP 8, а я не хочу следовать этим решениям.

Настройка

См. файл params.php

Использование

$ php gpsdPROXY.php

К демону можно подключиться через BSD socket или websocket по адресу, указанному в params.php.

Управление

Демон проверяет, не запущен ли он уже, и не запускается вторично.
Параметры команд gpsd не поддерживаются, зато имеются дополнительные параметры:

  • параметр "subscribe":"TPV|AIS" для команд ?POLL и ?WATCH={"enable":true,"json":true}.
    Параметр указывает возвращать только данные TPV или AIS, но не то и другое. Например:
    ?POLL={"subscribe":"AIS"} возвращает класс "POLL" с данными "ais":[], вместо "tpv":[].
  • параметр "minPeriod":"", в сек. для команды WATCH={"enable":true,"json":true}. Нормально данные отсылаются так часто, как они приходят от gpsd. Указание этого параметра заставляет демон отсылать данные не чаще указанного количества секунд. Например, команда:
    WATCH={"enable":true,"json":true,"minPeriod":"2"} посылает данные каждые две секунды, или реже, по мере получения данных.

Результат

Демон возвращает данные, как описано в документации к gpsd, за исключением:

  • ответ DEVICES на команду WATCH содержит только одно устройство -- сам демон. Как следствие -- не надо объединять сходные данные от разных устройств: это уже делает демон.
  • массив sky в объекте POLL пуст
  • объект AIS отсутствует в ответе команды WATCH, вместо этого посылается отдельный объект
  • в объект POLL и ответ команды WATCH добавлен массив ais с ключами mmsi и данными в формате, описанном в AIS DUMP FORMATS, за исключением:
  • скорость в м/сек
  • координаты в десятичных градусах
  • углы в градусах
  • осадка в метрах
  • длина в метрах
  • ширина в метрах
  • поле 'second' отсутствует, но есть поле 'timestamp' с временем unix
  • Добавлен массив ALARM с информацией "человек за бортом" и обнаружения столкновений.

Пример клиентского кода

webSocket = new WebSocket("ws://"+gpsdProxyHost+":"+gpsdProxyPort);

webSocket.onopen = function(e) {
	console.log("spatialWebSocket open: Connection established");
};

webSocket.onmessage = function(event) {
	let data;

	data = JSON.parse(event.data);

	switch(data.class){
	case 'VERSION':
		console.log('webSocket: Handshaiking with gpsd begin: VERSION recieved. Sending WATCH');
		webSocket.send('?WATCH={"enable":true,"json":true,"subscribe":"TPV,AIS,ALARM","minPeriod":"0"};');
		break;
	case 'DEVICES':
		console.log('webSocket: Handshaiking with gpsd proceed: DEVICES recieved');
		break;
	case 'WATCH':
		console.log('webSocket: Handshaiking with gpsd complit: WATCH recieved.');
		break;
	case 'POLL':
		break;
	case 'TPV':
		realtimeTPVupdate(data);
		break;
	case 'AIS':
		realtimeAISupdate(data);
		break;
	case 'ALARM':
		for(const alarmType in data.alarms){
			switch(alarmType){
			case 'MOB':
				realtimeMOBupdate(data.alarms.MOB);
				break;
			case 'collisions':
				realtimeCollisionsUpdate(data.alarms.collisions);
				break;
			};
		};
		break;
	}
};

webSocket.onclose = function(event) {
	console.log('webSocket closed: connection broken with code '+event.code+' by reason ${event.reason}');
};

webSocket.onerror = function(error) {
	console.log('webSocket error');
};

Поддержка

Сообщество ВКонтакте

Индивидуальная платная консультация

Вы можете сделать пожертвование через ЮМани.