diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e522ce..89bc79f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # CHANGELOG ## not released +- parser: Added support for latency in receiver messages (OGNSDR) (fixes #87) - parser: Added support for reference_timestamp with tzinfo (fixes #84) - parser: Fixed textual altitude part (fixes #81) - parser: Skip keys where value is "None" diff --git a/ogn/parser/aprs_comment/ogn_parser.py b/ogn/parser/aprs_comment/ogn_parser.py index 3829fac..64d8c9f 100644 --- a/ogn/parser/aprs_comment/ogn_parser.py +++ b/ogn/parser/aprs_comment/ogn_parser.py @@ -28,52 +28,64 @@ class OgnParser(BaseParser): 'beacon_type': 'aprs_receiver'} def parse_aircraft_beacon(self, aprs_comment): - ab_match = self.aircraft_pattern.match(aprs_comment) - if ab_match: - return {k: v for (k, v) in - {'address_type': int(ab_match.group('details'), 16) & 0b00000011, - 'aircraft_type': (int(ab_match.group('details'), 16) & 0b01111100) >> 2, - 'stealth': (int(ab_match.group('details'), 16) & 0b10000000) >> 7 == 1, - 'address': ab_match.group('address'), - 'climb_rate': int(ab_match.group('climb_rate')) * FPM_TO_MS if ab_match.group('climb_rate') else None, - 'turn_rate': float(ab_match.group('turn_rate')) * HPM_TO_DEGS if ab_match.group('turn_rate') else None, - 'flightlevel': float(ab_match.group('flight_level')) if ab_match.group('flight_level') else None, - 'signal_quality': float(ab_match.group('signal_quality')) if ab_match.group('signal_quality') else None, - 'error_count': int(ab_match.group('errors')) if ab_match.group('errors') else None, - 'frequency_offset': float(ab_match.group('frequency_offset')) if ab_match.group('frequency_offset') else None, - 'gps_quality': {'horizontal': int(ab_match.group('gps_quality_horizontal')), - 'vertical': int(ab_match.group('gps_quality_vertical'))} if ab_match.group('gps_quality') else None, - 'software_version': float(ab_match.group('flarm_software_version')) if ab_match.group('flarm_software_version') else None, - 'hardware_version': int(ab_match.group('flarm_hardware_version'), 16) if ab_match.group('flarm_hardware_version') else None, - 'real_address': ab_match.group('flarm_id') if ab_match.group('flarm_id') else None, - 'signal_power': float(ab_match.group('signal_power')) if ab_match.group('signal_power') else None, - 'proximity': [hear[4:] for hear in ab_match.group('proximity').split(" ")] if ab_match.group('proximity') else None}.items() if v is not None} + match = self.aircraft_pattern.match(aprs_comment) + if match: + result = {} + if match.group('details'): + result.update({ + 'address_type': int(match.group('details'), 16) & 0b00000011, + 'aircraft_type': (int(match.group('details'), 16) & 0b01111100) >> 2, + 'stealth': (int(match.group('details'), 16) & 0b10000000) >> 7 == 1, + 'address': match.group('address'), + }) + if match.group('climb_rate'): result['climb_rate'] = int(match.group('climb_rate')) * FPM_TO_MS + if match.group('turn_rate'): result['turn_rate'] = float(match.group('turn_rate')) * HPM_TO_DEGS + if match.group('flight_level'): result['flightlevel'] = float(match.group('flight_level')) + if match.group('signal_quality'): result['signal_quality'] = float(match.group('signal_quality')) + if match.group('errors'): result['error_count'] = int(match.group('errors')) + if match.group('frequency_offset'): result['frequency_offset'] = float(match.group('frequency_offset')) + if match.group('gps_quality'): + result.update({ + 'gps_quality': { + 'horizontal': int(match.group('gps_quality_horizontal')), + 'vertical': int(match.group('gps_quality_vertical')) + } + }) + if match.group('flarm_software_version'): result['software_version'] = float(match.group('flarm_software_version')) + if match.group('flarm_hardware_version'): result['hardware_version'] = int(match.group('flarm_hardware_version'), 16) + if match.group('flarm_id'): result['real_address'] = match.group('flarm_id') + if match.group('signal_power'): result['signal_power'] = float(match.group('signal_power')) + if match.group('proximity'): result['proximity'] = [hear[4:] for hear in match.group('proximity').split(' ')] + return result else: return None def parse_receiver_beacon(self, aprs_comment): - rb_match = self.receiver_pattern.match(aprs_comment) - if rb_match: - return {k: v for (k, v) in - {'version': rb_match.group('version'), - 'platform': rb_match.group('platform'), - 'cpu_load': float(rb_match.group('cpu_load')), - 'free_ram': float(rb_match.group('ram_free')), - 'total_ram': float(rb_match.group('ram_total')), - 'ntp_error': float(rb_match.group('ntp_offset')), - 'rt_crystal_correction': float(rb_match.group('ntp_correction')), - 'voltage': float(rb_match.group('voltage')) if rb_match.group('voltage') else None, - 'amperage': float(rb_match.group('amperage')) if rb_match.group('amperage') else None, - 'cpu_temp': float(rb_match.group('cpu_temperature')) if rb_match.group('cpu_temperature') else None, - 'senders_visible': int(rb_match.group('visible_senders')) if rb_match.group('visible_senders') else None, - 'senders_total': int(rb_match.group('senders')) if rb_match.group('senders') else None, - 'rec_crystal_correction': int(rb_match.group('rf_correction_manual')) if rb_match.group('rf_correction_manual') else None, - 'rec_crystal_correction_fine': float(rb_match.group('rf_correction_automatic')) if rb_match.group('rf_correction_automatic') else None, - 'rec_input_noise': float(rb_match.group('signal_quality')) if rb_match.group('signal_quality') else None, - 'senders_signal': float(rb_match.group('senders_signal_quality')) if rb_match.group('senders_signal_quality') else None, - 'senders_messages': float(rb_match.group('senders_messages')) if rb_match.group('senders_messages') else None, - 'good_senders_signal': float(rb_match.group('good_senders_signal_quality')) if rb_match.group('good_senders_signal_quality') else None, - 'good_senders': float(rb_match.group('good_senders')) if rb_match.group('good_senders') else None, - 'good_and_bad_senders': float(rb_match.group('good_and_bad_senders')) if rb_match.group('good_and_bad_senders') else None}.items() if v is not None} + match = self.receiver_pattern.match(aprs_comment) + if match: + result = { + 'version': match.group('version'), + 'platform': match.group('platform'), + 'cpu_load': float(match.group('cpu_load')), + 'free_ram': float(match.group('ram_free')), + 'total_ram': float(match.group('ram_total')), + 'ntp_error': float(match.group('ntp_offset')), + 'rt_crystal_correction': float(match.group('ntp_correction')) + } + if match.group('voltage'): result['voltage'] = float(match.group('voltage')) + if match.group('amperage'): result['amperage'] = float(match.group('amperage')) + if match.group('cpu_temperature'): result['cpu_temp'] = float(match.group('cpu_temperature')) + if match.group('visible_senders'): result['senders_visible'] = int(match.group('visible_senders')) + if match.group('senders'): result['senders_total'] = int(match.group('senders')) + if match.group('latency'): result['latency'] = float(match.group('latency')) + if match.group('rf_correction_manual'): result['rec_crystal_correction'] = int(match.group('rf_correction_manual')) + if match.group('rf_correction_automatic'): result['rec_crystal_correction_fine'] = float(match.group('rf_correction_automatic')) + if match.group('signal_quality'): result['rec_input_noise'] = float(match.group('signal_quality')) + if match.group('senders_signal_quality'): result['senders_signal'] = float(match.group('senders_signal_quality')) + if match.group('senders_messages'): result['senders_messages'] = float(match.group('senders_messages')) + if match.group('good_senders_signal_quality'): result['good_senders_signal'] = float(match.group('good_senders_signal_quality')) + if match.group('good_senders'): result['good_senders'] = float(match.group('good_senders')) + if match.group('good_and_bad_senders'): result['good_and_bad_senders'] = float(match.group('good_and_bad_senders')) + return result else: return None diff --git a/ogn/parser/pattern.py b/ogn/parser/pattern.py index 0f3dc80..55e0ee0 100644 --- a/ogn/parser/pattern.py +++ b/ogn/parser/pattern.py @@ -183,6 +183,7 @@ PATTERN_RECEIVER_BEACON = re.compile(r""" (?:(?P[\d.]+)A\s)? (?:(?P[+-][\d.]+)C\s*)? (?:(?P\d+)/(?P\d+)Acfts\[1h\]\s*)? + (Lat\:(?P\d+\.\d+)s\s*)? (?:RF: (?: (?P[+-][\d]+)