|
1 | 1 | from datetime import datetime, timezone |
2 | 2 |
|
3 | | -from ogn.parser.utils import createTimestamp, parseAngle, KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER, INCH_TO_MM, fahrenheit_to_celsius, CheapRuler, normalized_quality |
| 3 | +from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS, createTimestamp, parseAngle, KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER, INCH_TO_MM, fahrenheit_to_celsius, CheapRuler, normalized_quality |
4 | 4 | from ogn.parser.pattern import PATTERN_APRS, PATTERN_APRS_POSITION, PATTERN_APRS_POSITION_WEATHER, PATTERN_APRS_STATUS, PATTERN_SERVER |
5 | 5 | from ogn.parser.exceptions import AprsParseError, OgnParseError |
6 | 6 |
|
|
19 | 19 | from ogn.parser.aprs_comment.microtrak_parser import MicrotrakParser |
20 | 20 | from ogn.parser.aprs_comment.generic_parser import GenericParser |
21 | 21 |
|
| 22 | +from ogn_parser import parse as rust_parse |
| 23 | + |
22 | 24 | positions = {} |
23 | 25 | server_timestamp = None |
24 | 26 |
|
| 27 | +mapping = { |
| 28 | + 'OGCAPT': 'capturs', |
| 29 | + 'OGNFNT': 'fanet', |
| 30 | + 'OGFLR': 'flarm', |
| 31 | + 'OGFLR6': 'flarm', |
| 32 | + 'OGFLR7': 'flarm', |
| 33 | + 'OGFLYM': 'flymaster', |
| 34 | + 'OGINRE': 'inreach', |
| 35 | + 'OGLT24': 'lt24', |
| 36 | + 'OGNMTK': 'microtrak', |
| 37 | + 'OGNAVI': 'naviter', |
| 38 | + 'OGNSDR': 'receiver', |
| 39 | + 'OGNSKY': 'safesky', |
| 40 | + 'OGPAW': 'pilot_aware', |
| 41 | + 'OGSKYL': 'skylines', |
| 42 | + 'OGSPID': 'spider', |
| 43 | + 'OGSPOT': 'spot', |
| 44 | + 'OGNTRK': 'tracker', |
| 45 | +} |
| 46 | + |
25 | 47 |
|
26 | | -def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use_server_timestamp=True): |
| 48 | +def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use_server_timestamp=True, use_rust_parser=False): |
27 | 49 | global server_timestamp |
28 | 50 |
|
29 | 51 | if use_server_timestamp is True: |
30 | 52 | reference_timestamp = server_timestamp or datetime.now(timezone.utc) |
31 | 53 | elif reference_timestamp is None: |
32 | 54 | reference_timestamp = datetime.now(timezone.utc) |
33 | 55 |
|
34 | | - message = parse_aprs(aprs_message, reference_timestamp=reference_timestamp) |
35 | | - if message['aprs_type'] == 'position' or message['aprs_type'] == 'status': |
36 | | - try: |
37 | | - message.update(parse_comment(message['comment'], |
38 | | - dstcall=message['dstcall'], |
39 | | - aprs_type=message['aprs_type'])) |
40 | | - except Exception: |
41 | | - raise OgnParseError(f"dstcall: {message['dstcall']}, aprs_type: {message['aprs_type']}, comment: {message['comment']}") |
| 56 | + if use_rust_parser: |
| 57 | + rust_zeug = rust_parse(aprs_message) |
| 58 | + message = {'raw_message': aprs_message, 'reference_timestamp': reference_timestamp} |
| 59 | + if parser_error := rust_zeug.get('parsererror'): |
| 60 | + message['aprs_type'] = 'comment' |
| 61 | + message['comment'] = str(parser_error) |
| 62 | + elif aprs_packet := rust_zeug.get('aprspacket'): |
| 63 | + message.update({ |
| 64 | + 'aprs_type': 'position', |
| 65 | + 'beacon_type': mapping.get(aprs_packet['to'], 'unknown'), |
| 66 | + 'name': aprs_packet['from'], |
| 67 | + 'dstcall': aprs_packet['to'], |
| 68 | + }) |
| 69 | + if via := aprs_packet.get('via'): |
| 70 | + message['receiver_name'] = via[-1] |
| 71 | + if aprs_packet['via'][0] != 'TCPIP*' and aprs_packet['via'][0].endswith('*'): message['relay'] = aprs_packet['via'][0][:-1] |
| 72 | + if position := aprs_packet.get('position'): |
| 73 | + message.update({ |
| 74 | + 'latitude': position['latitude'], |
| 75 | + 'longitude': position['longitude'], |
| 76 | + 'symboltable': position['symbol_table'], |
| 77 | + 'symbolcode': position['symbol_code'], |
| 78 | + }) |
| 79 | + if 'timestamp' in position: message['timestamp'] = createTimestamp(position['timestamp'], reference_timestamp) |
| 80 | + |
| 81 | + if 'wind_direction' in position: |
| 82 | + message['aprs_type'] = 'position_weather' |
| 83 | + if 'wind_direction' in position: message["wind_direction"] = position['wind_direction'] |
| 84 | + if 'wind_speed' in position: message["wind_speed"] = position['wind_speed'] * KNOTS_TO_MS / KPH_TO_MS |
| 85 | + if 'gust' in position: message['wind_speed_peak'] = position['gust'] * KNOTS_TO_MS / KPH_TO_MS |
| 86 | + if 'temperature' in position: message['temperature'] = fahrenheit_to_celsius(position['temperature']) |
| 87 | + if 'rainfall_1h' in position: message['rainfall_1h'] = position['rainfall_1h'] / 100.0 * INCH_TO_MM |
| 88 | + if 'rainfall_24h' in position: message['rainfall_24h'] = position['rainfall_24h'] / 100.0 * INCH_TO_MM |
| 89 | + if 'humidity' in position: message['humidity'] = 1. if position['humidity'] == 0 else position['humidity'] * 0.01 |
| 90 | + if 'barometric_pressure' in position: message['barometric_pressure'] = position['barometric_pressure'] |
| 91 | + |
| 92 | + if 'course' in position: message["track"] = position['course'] |
| 93 | + if 'speed' in position: message["ground_speed"] = position['speed'] * KNOTS_TO_MS / KPH_TO_MS |
| 94 | + if 'altitude' in position: message["altitude"] = position['altitude'] * FEETS_TO_METER |
| 95 | + |
| 96 | + if 'reserved' in position: message['reserved'] = position['reserved'] |
| 97 | + if 'address_type' in position: message['address_type'] = position['address_type'] |
| 98 | + if 'aircraft_type' in position: message['aircraft_type'] = position['aircraft_type'] |
| 99 | + if 'is_notrack' in position: message['no-tracking'] = position['is_notrack'] |
| 100 | + if 'is_stealth' in position: message['stealth'] = position['is_stealth'] |
| 101 | + if 'address' in position: message['address'] = f"{position['address']:06X}" |
| 102 | + |
| 103 | + if 'climb_rate' in position: message["climb_rate"] = position['climb_rate'] * FPM_TO_MS |
| 104 | + if 'turn_rate' in position: message["turn_rate"] = position['turn_rate'] * HPM_TO_DEGS |
| 105 | + if 'signal_quality' in position: message["signal_quality"] = position['signal_quality'] |
| 106 | + if 'error' in position: message["error_count"] = position['error'] |
| 107 | + if 'frequency_offset' in position: message["frequency_offset"] = position['frequency_offset'] |
| 108 | + if 'gps_quality' in position: message["gps_quality"] = position['gps_quality'] |
| 109 | + if 'flight_level' in position: message["flightlevel"] = position['flight_level'] |
| 110 | + if 'signal_power' in position: message["signal_power"] = position['signal_power'] |
| 111 | + if 'software_version' in position: message["software_version"] = position['software_version'] |
| 112 | + if 'hardware_version' in position: message["hardware_version"] = position['hardware_version'] |
| 113 | + if 'original_address' in position: message["real_address"] = f"{position['original_address']:06X}" |
| 114 | + |
| 115 | + if 'unparsed' in position: message["user_comment"] = position['unparsed'] |
| 116 | + |
| 117 | + elif status := aprs_packet.get('status'): |
| 118 | + message['aprs_type'] = 'status' |
| 119 | + if 'timestamp' in status: message['timestamp'] = createTimestamp(status['timestamp'], reference_timestamp) |
| 120 | + |
| 121 | + if 'version' in status: message["version"] = status['version'] |
| 122 | + if 'platform' in status: message["platform"] = status['platform'] |
| 123 | + if 'cpu_load' in status: message["cpu_load"] = status['cpu_load'] |
| 124 | + if 'ram_free' in status: message["free_ram"] = status['ram_free'] |
| 125 | + if 'ram_total' in status: message["total_ram"] = status['ram_total'] |
| 126 | + if 'ntp_offset' in status: message["ntp_error"] = status['ntp_offset'] |
| 127 | + if 'ntp_correction' in status: message["rt_crystal_correction"] = status['ntp_correction'] |
| 128 | + if 'voltage' in status: message["voltage"] = status['voltage'] |
| 129 | + if 'amperage' in status: message["amperage"] = status['amperage'] |
| 130 | + if 'cpu_temperature' in status: message["cpu_temp"] = status['cpu_temperature'] |
| 131 | + if 'visible_senders' in status: message["senders_visible"] = status['visible_senders'] |
| 132 | + if 'latency' in status: message["latency"] = status['latency'] |
| 133 | + if 'senders' in status: message["senders_total"] = status['senders'] |
| 134 | + if 'rf_correction_manual' in status: message["rec_crystal_correction"] = status['rf_correction_manual'] |
| 135 | + if 'rf_correction_automatic' in status: message["rec_crystal_correction_fine"] = status['rf_correction_automatic'] |
| 136 | + if 'noise' in status: message["rec_input_noise"] = status['noise'] |
| 137 | + if 'senders_signal_quality' in status: message["senders_signal"] = status['senders_signal_quality'] |
| 138 | + if 'senders_messages' in status: message["senders_messages"] = status['senders_messages'] |
| 139 | + if 'good_senders_signal_quality' in status: message["good_senders_signal"] = status['good_senders_signal_quality'] |
| 140 | + if 'good_senders' in status: message["good_senders"] = status['good_senders'] |
| 141 | + if 'good_and_bad_senders' in status: message["good_and_bad_senders"] = status['good_and_bad_senders'] |
| 142 | + |
| 143 | + if 'unparsed' in status: message["user_comment"] = status['unparsed'] |
| 144 | + else: |
| 145 | + raise ValueError("WTF") |
| 146 | + |
| 147 | + else: |
| 148 | + raise ValueError("WTF") |
| 149 | + |
| 150 | + else: |
| 151 | + message = parse_aprs(aprs_message, reference_timestamp=reference_timestamp) |
| 152 | + if message['aprs_type'] == 'position' or message['aprs_type'] == 'status': |
| 153 | + try: |
| 154 | + message.update(parse_comment(message['comment'], dstcall=message['dstcall'], aprs_type=message['aprs_type'])) |
| 155 | + except Exception: |
| 156 | + raise OgnParseError(f"dstcall: {message['dstcall']}, aprs_type: {message['aprs_type']}, comment: {message['comment']}") |
42 | 157 |
|
43 | 158 | if message['aprs_type'].startswith('position') and calculate_relations is True: |
44 | 159 | positions[message['name']] = (message['longitude'], message['latitude']) |
@@ -112,7 +227,7 @@ def parse_aprs(message, reference_timestamp=None): |
112 | 227 |
|
113 | 228 | 'name': match.group('callsign'), |
114 | 229 | 'dstcall': match.group('dstcall'), |
115 | | - 'relay': match.group('relay') if match.group('relay') else None, |
| 230 | + 'relay': match.group('relay'), |
116 | 231 | 'receiver_name': match.group('receiver'), |
117 | 232 | 'timestamp': createTimestamp(match_position_weather.group('time'), reference_timestamp), |
118 | 233 | 'latitude': parseAngle('0' + match_position_weather.group('latitude')) * # noqa: W504 |
|
0 commit comments