diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e485b3..b822076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Unreleased - parser: Added support for heared aircrafts -- parser: Added support for naviter beacons +- parser: Added support for OGNSDR (receiver), OGNTRK (ogn tracker), OGNFLR (flarm) and OGNAV (Naviter) beacons - client: Allow client to do sequential connect-disconnect ## 0.7.1 - 2017-06-05 diff --git a/README.md b/README.md index 7888dfa..b9acc7a 100644 --- a/README.md +++ b/README.md @@ -15,27 +15,25 @@ A full featured gateway with build-in database is provided by [ogn-python](https Parse APRS/OGN packet. ``` -from ogn.parser import parse_aprs, parse_ogn_beacon +from ogn.parser import parse from datetime import date, time -beacon = parse_aprs("FLRDDDEAD>APRS,qAS,EDER:/114500h5029.86N/00956.98E'342/049/A=005524 id0ADDDEAD -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5", - reference_date=date(2016,1,1), reference_time=time(11,46)) -beacon.update(parse_ogn_beacon(beacon['comment'])) +beacon = parse("FLRDDDEAD>APRS,qAS,EDER:/114500h5029.86N/00956.98E'342/049/A=005524 id0ADDDEAD -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5", + reference_date=date(2016,1,1), reference_time=time(11,46)) ``` Connect to OGN and display all incoming beacons. ``` from ogn.client import AprsClient -from ogn.parser import parse_aprs, parse_ogn_beacon, ParseError +from ogn.parser import parse, ParseError def process_beacon(raw_message): if raw_message[0] == '#': print('Server Status: {}'.format(raw_message)) return try: - beacon = parse_aprs(raw_message) - beacon.update(parse_ogn_beacon(beacon['comment'])) + beacon = parse(raw_message) print('Received {beacon_type} from {name}'.format(**beacon)) except ParseError as e: print('Error, {}'.format(e.message)) diff --git a/ogn/parser/__init__.py b/ogn/parser/__init__.py index 5bcc93f..369d1ca 100644 --- a/ogn/parser/__init__.py +++ b/ogn/parser/__init__.py @@ -1,2 +1,3 @@ -from ogn.parser.parse import parse_aprs, parse_ogn_beacon, parse_receiver_beacon, parse_aircraft_beacon # flake8: noqa +from ogn.parser import parse as parse_module # only for test functions. Without this a mock of parse would mock the function instead of the module +from ogn.parser.parse import parse, parse_aprs, parse_comment # flake8: noqa from ogn.parser.exceptions import ParseError, AprsParseError, OgnParseError, AmbigousTimeError # flake8: noqa diff --git a/ogn/parser/parse.py b/ogn/parser/parse.py index f0bf5e7..ca80249 100644 --- a/ogn/parser/parse.py +++ b/ogn/parser/parse.py @@ -17,26 +17,25 @@ from ogn.parser.parse_receiver import parse_position as parse_receiver_position from ogn.parser.parse_receiver import parse_status as parse_receiver_status -def parse_aprs(message, reference_date=None, reference_time=None): +def parse(aprs_message, reference_date=None, reference_time=None): if reference_date is None: now = datetime.utcnow() reference_date = now.date() reference_time = now.time() + message = parse_aprs(aprs_message, reference_date, reference_time) + message.update(parse_comment(message['comment'], dstcall=message['dstcall'], aprs_type=message['aprs_type'])) + return message + + +def parse_aprs(message, reference_date=None, reference_time=None): match_position = re.search(PATTERN_APRS_POSITION, message) if match_position: - if match_position.group('time_hhmmss'): - timestamp = createTimestamp(match_position.group('time_hhmmss'), reference_date, reference_time) - else: - timestamp_ddmmhh = match_position.group('time_ddmmhh') - reference_date = reference_date.replace(day=int(timestamp_ddmmhh[:2])) - timestamp = createTimestamp(timestamp_ddmmhh[2:] + '00', reference_date) - return {'name': match_position.group('callsign'), 'dstcall': match_position.group('dstcall'), 'relay': match_position.group('relay') if match_position.group('relay') else None, 'receiver_name': match_position.group('receiver'), - 'timestamp': timestamp, + 'timestamp': createTimestamp(match_position.group('time'), reference_date, reference_time), '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'), @@ -46,7 +45,7 @@ def parse_aprs(message, reference_date=None, reference_time=None): 'track': int(match_position.group('course')) if match_position.group('course_extension') else None, 'ground_speed': int(match_position.group('ground_speed')) * kts2kmh if match_position.group('ground_speed') else None, 'altitude': int(match_position.group('altitude')) * feet2m, - 'comment': match_position.group('comment'), + 'comment': match_position.group('comment') if match_position.group('comment') else "", 'aprs_type': 'position'} match_status = re.search(PATTERN_APRS_STATUS, message) @@ -55,13 +54,13 @@ def parse_aprs(message, reference_date=None, reference_time=None): 'dstcall': match_status.group('dstcall'), 'receiver_name': match_status.group('receiver'), 'timestamp': createTimestamp(match_status.group('time'), reference_date, reference_time), - 'comment': match_status.group('comment'), + 'comment': match_status.group('comment') if match_status.group('comment') else "", 'aprs_type': 'status'} raise AprsParseError(message) -def parse_ogn_beacon(aprs_comment, dstcall="APRS", aprs_type="position"): +def parse_comment(aprs_comment, dstcall="APRS", aprs_type="position"): if dstcall == "APRS": # this can be a receiver or an aircraft if not aprs_comment: return {'beacon_type': 'receiver_beacon'} diff --git a/ogn/parser/parse_receiver.py b/ogn/parser/parse_receiver.py index ab919ee..97ce78b 100644 --- a/ogn/parser/parse_receiver.py +++ b/ogn/parser/parse_receiver.py @@ -4,8 +4,11 @@ from ogn.parser.pattern import PATTERN_RECEIVER_POSITION, PATTERN_RECEIVER_STATU def parse_position(aprs_comment): - match = re.search(PATTERN_RECEIVER_POSITION, aprs_comment) - return {'user_comment': match.group('user_comment') if match.group('user_comment') else None} + if aprs_comment is None: + return {} + else: + match = re.search(PATTERN_RECEIVER_POSITION, aprs_comment) + return {'user_comment': match.group('user_comment') if match.group('user_comment') else None} def parse_status(aprs_comment): diff --git a/ogn/parser/pattern.py b/ogn/parser/pattern.py index aadde63..936ac63 100644 --- a/ogn/parser/pattern.py +++ b/ogn/parser/pattern.py @@ -1,8 +1,8 @@ import re -PATTERN_APRS_POSITION = re.compile(r"^(?P.+?)>(?P[A-Z0-9]+),((?P[A-Za-z0-9]+)\*)?.*,(?P.+?):/((?P\d{6})h|(?P\d{6})z)(?P\d{4}\.\d{2})(?PN|S)(?P.)(?P\d{5}\.\d{2})(?PE|W)(?P.)(?P(?P\d{3})/(?P\d{3}))?/A=(?P\d{6})(?P\s!W((?P\d)(?P\d))!)?(?:\s(?P.*))?$") -PATTERN_APRS_STATUS = re.compile(r"^(?P.+?)>(?P[A-Z0-9]+),.+,(?P.+?):>(?P