2016-02-28 11:11:16 +00:00
|
|
|
import re
|
|
|
|
from datetime import datetime
|
|
|
|
|
2018-04-30 19:00:08 +00:00
|
|
|
from ogn.parser.utils import createTimestamp, parseAngle, KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER
|
2018-04-12 21:24:52 +00:00
|
|
|
from ogn.parser.pattern import PATTERN_APRS, PATTERN_APRS_POSITION, PATTERN_APRS_STATUS, PATTERN_SERVER
|
2019-06-03 20:17:55 +00:00
|
|
|
from ogn.parser.exceptions import AprsParseError
|
2016-02-28 11:11:16 +00:00
|
|
|
|
2017-10-05 08:36:53 +00:00
|
|
|
from ogn.parser.aprs_comment.ogn_parser import OgnParser
|
2018-04-10 16:54:30 +00:00
|
|
|
from ogn.parser.aprs_comment.fanet_parser import FanetParser
|
2017-10-05 08:36:53 +00:00
|
|
|
from ogn.parser.aprs_comment.lt24_parser import LT24Parser
|
|
|
|
from ogn.parser.aprs_comment.naviter_parser import NaviterParser
|
|
|
|
from ogn.parser.aprs_comment.flarm_parser import FlarmParser
|
|
|
|
from ogn.parser.aprs_comment.tracker_parser import TrackerParser
|
|
|
|
from ogn.parser.aprs_comment.receiver_parser import ReceiverParser
|
|
|
|
from ogn.parser.aprs_comment.skylines_parser import SkylinesParser
|
|
|
|
from ogn.parser.aprs_comment.spider_parser import SpiderParser
|
|
|
|
from ogn.parser.aprs_comment.spot_parser import SpotParser
|
2019-06-06 03:11:59 +00:00
|
|
|
from ogn.parser.aprs_comment.inreach_parser import InreachParser
|
2019-06-03 20:17:55 +00:00
|
|
|
from ogn.parser.aprs_comment.generic_parser import GenericParser
|
2017-09-30 06:48:56 +00:00
|
|
|
|
2016-02-28 11:11:16 +00:00
|
|
|
|
2018-05-01 09:21:28 +00:00
|
|
|
def parse(aprs_message, reference_timestamp=None):
|
|
|
|
if reference_timestamp is None:
|
|
|
|
reference_timestamp = datetime.utcnow()
|
2016-02-28 11:11:16 +00:00
|
|
|
|
2018-05-01 09:21:28 +00:00
|
|
|
message = parse_aprs(aprs_message, reference_timestamp)
|
2018-03-18 16:55:01 +00:00
|
|
|
if message['aprs_type'] == 'position' or message['aprs_type'] == 'status':
|
|
|
|
message.update(parse_comment(message['comment'],
|
|
|
|
dstcall=message['dstcall'],
|
|
|
|
aprs_type=message['aprs_type']))
|
2017-09-30 16:25:02 +00:00
|
|
|
return message
|
|
|
|
|
|
|
|
|
2018-05-01 09:21:28 +00:00
|
|
|
def parse_aprs(message, reference_timestamp=None):
|
|
|
|
if reference_timestamp is None:
|
|
|
|
reference_timestamp = datetime.utcnow()
|
|
|
|
|
2018-05-03 05:47:38 +00:00
|
|
|
result = {'raw_message': message,
|
|
|
|
'reference_timestamp': reference_timestamp}
|
|
|
|
|
2018-03-17 10:10:19 +00:00
|
|
|
if message and message[0] == '#':
|
2018-04-12 21:24:52 +00:00
|
|
|
match_server = re.search(PATTERN_SERVER, message)
|
2018-03-17 10:10:19 +00:00
|
|
|
if match_server:
|
2018-05-03 05:47:38 +00:00
|
|
|
result.update({
|
|
|
|
'version': match_server.group('version'),
|
|
|
|
'timestamp': datetime.strptime(match_server.group('timestamp'), "%d %b %Y %H:%M:%S %Z"),
|
|
|
|
'server': match_server.group('server'),
|
|
|
|
'ip_address': match_server.group('ip_address'),
|
|
|
|
'port': match_server.group('port'),
|
|
|
|
'aprs_type': 'server'})
|
2018-03-17 10:10:19 +00:00
|
|
|
else:
|
2018-05-03 05:47:38 +00:00
|
|
|
result.update({
|
|
|
|
'comment': message,
|
|
|
|
'aprs_type': 'comment'})
|
2018-03-17 10:10:19 +00:00
|
|
|
|
2018-05-03 05:47:38 +00:00
|
|
|
else:
|
|
|
|
match = re.search(PATTERN_APRS, message)
|
|
|
|
if match:
|
|
|
|
aprs_type = 'position' if match.group('aprs_type') == '/' else 'status'
|
|
|
|
result.update({'aprs_type': aprs_type})
|
|
|
|
aprs_body = match.group('aprs_body')
|
|
|
|
if aprs_type == 'position':
|
|
|
|
match_position = re.search(PATTERN_APRS_POSITION, aprs_body)
|
|
|
|
if match_position:
|
|
|
|
result.update({
|
|
|
|
'name': match.group('callsign'),
|
2018-04-10 06:33:48 +00:00
|
|
|
'dstcall': match.group('dstcall'),
|
|
|
|
'relay': match.group('relay') if match.group('relay') else None,
|
|
|
|
'receiver_name': match.group('receiver'),
|
2018-05-01 09:21:28 +00:00
|
|
|
'timestamp': createTimestamp(match_position.group('time'), reference_timestamp),
|
2018-04-10 06:33:48 +00:00
|
|
|
'latitude': parseAngle('0' + match_position.group('latitude') + (match_position.group('latitude_enhancement') or '0')) *
|
|
|
|
(-1 if match_position.group('latitude_sign') == 'S' else 1),
|
|
|
|
'symboltable': match_position.group('symbol_table'),
|
|
|
|
'longitude': parseAngle(match_position.group('longitude') + (match_position.group('longitude_enhancement') or '0')) *
|
|
|
|
(-1 if match_position.group('longitude_sign') == 'W' else 1),
|
|
|
|
'symbolcode': match_position.group('symbol'),
|
|
|
|
'track': int(match_position.group('course')) if match_position.group('course_extension') else None,
|
2018-04-30 19:00:08 +00:00
|
|
|
'ground_speed': int(match_position.group('ground_speed')) * KNOTS_TO_MS / KPH_TO_MS if match_position.group('ground_speed') else None,
|
|
|
|
'altitude': int(match_position.group('altitude')) * FEETS_TO_METER,
|
2018-05-03 05:47:38 +00:00
|
|
|
'comment': match_position.group('comment') if match_position.group('comment') else ""})
|
|
|
|
else:
|
|
|
|
raise AprsParseError(message)
|
|
|
|
elif aprs_type == 'status':
|
|
|
|
match_status = re.search(PATTERN_APRS_STATUS, aprs_body)
|
|
|
|
if match_status:
|
|
|
|
result.update({
|
|
|
|
'name': match.group('callsign'),
|
2018-04-10 06:33:48 +00:00
|
|
|
'dstcall': match.group('dstcall'),
|
|
|
|
'receiver_name': match.group('receiver'),
|
2018-05-01 09:21:28 +00:00
|
|
|
'timestamp': createTimestamp(match_status.group('time'), reference_timestamp),
|
2018-05-03 05:47:38 +00:00
|
|
|
'comment': match_status.group('comment') if match_status.group('comment') else ""})
|
|
|
|
else:
|
|
|
|
raise AprsParseError(message)
|
|
|
|
else:
|
|
|
|
raise AprsParseError(message)
|
2016-02-28 11:11:16 +00:00
|
|
|
|
2018-05-03 05:47:38 +00:00
|
|
|
return result
|
2016-02-28 11:11:16 +00:00
|
|
|
|
|
|
|
|
2017-10-05 08:36:53 +00:00
|
|
|
dstcall_parser_mapping = {'APRS': OgnParser(),
|
2018-04-10 16:54:30 +00:00
|
|
|
'OGNFNT': FanetParser(),
|
2017-10-05 08:36:53 +00:00
|
|
|
'OGFLR': FlarmParser(),
|
|
|
|
'OGNTRK': TrackerParser(),
|
|
|
|
'OGNSDR': ReceiverParser(),
|
|
|
|
'OGLT24': LT24Parser(),
|
|
|
|
'OGNAVI': NaviterParser(),
|
|
|
|
'OGSKYL': SkylinesParser(),
|
|
|
|
'OGSPID': SpiderParser(),
|
|
|
|
'OGSPOT': SpotParser(),
|
2019-06-06 03:11:59 +00:00
|
|
|
'OGINREACH': InreachParser(),
|
2019-06-03 20:17:55 +00:00
|
|
|
'GENERIC': GenericParser(),
|
2017-10-05 08:36:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def parse_comment(aprs_comment, dstcall='APRS', aprs_type="position"):
|
|
|
|
parser = dstcall_parser_mapping.get(dstcall)
|
|
|
|
if parser:
|
|
|
|
return parser.parse(aprs_comment, aprs_type)
|
2017-09-28 06:43:50 +00:00
|
|
|
else:
|
2019-06-03 20:17:55 +00:00
|
|
|
return dstcall_parser_mapping.get('GENERIC').parse(aprs_comment, aprs_type)
|