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() match_position = re.search(PATTERN_APRS_POSITION, message) if match_position: return {'name': match_position.group('callsign'), 'receiver_name': match_position.group('receiver'), 'dstcall': match_position.group('dstcall'), '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'), '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, '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')} match_status = re.search(PATTERN_APRS_STATUS, message) if match_status: return {'name': match_status.group('callsign'), 'receiver_name': match_status.group('receiver'), 'dstcall': match_status.group('dstcall'), 'timestamp': createTimestamp(match_status.group('time'), reference_date, reference_time), 'comment': match_status.group('comment')} raise AprsParseError(message)
def test_createTimestamp(self): test_data = [ ('000001', date(2015, 1, 10), time(0, 0, 1), datetime(2015, 1, 10, 0, 0, 1)), # packet from current day (on the tick) ('235959', date(2015, 1, 10), time(0, 0, 1), datetime(2015, 1, 9, 23, 59, 59)), # packet from previous day (2 seconds old) ('110000', date(2015, 1, 10), time(0, 0, 1), None), # packet 11 hours from future or 13 hours old ('123500', date(2015, 1, 10), time(23, 50, 0), datetime(2015, 1, 10, 12, 35, 0)), # packet from current day (11 hours old) ('000001', date(2015, 1, 10), time(23, 50, 0), datetime(2015, 1, 11, 0, 0, 1)), # packet from next day (11 minutes from future) ('000001', date(2015, 1, 10), None, datetime(2015, 1, 10, 0, 0, 1)), # first packet of a specific day ('235959', date(2015, 1, 10), None, datetime(2015, 1, 10, 23, 59, 59)), # last packet of a specific day ] for test in test_data: if test[3]: timestamp = createTimestamp(test[0], reference_date=test[1], reference_time=test[2]) self.assertEqual(timestamp, test[3]) else: with self.assertRaises(AmbigousTimeError): createTimestamp(test[0], reference_date=test[1], reference_time=test[2])
def parse(telnet_data): reference_timestamp = datetime.utcnow() try: return {'pps_offset': float(telnet_data[0:5]), 'frequency': float(telnet_data[9:16]), 'aircraft_type': int(telnet_data[20:24]), 'address_type': int(telnet_data[25]), 'address': telnet_data[27:33], 'timestamp': createTimestamp(telnet_data[34:40] + 'h', reference_timestamp), 'latitude': float(telnet_data[43:53]), 'longitude': float(telnet_data[54:64]), 'altitude': int(telnet_data[68:73]), 'climb_rate': float(telnet_data[74:80]), 'ground_speed': float(telnet_data[83:89]), 'track': float(telnet_data[92:98]), 'turn_rate': float(telnet_data[101:107]), 'magic_number': int(telnet_data[114:116]), 'gps_status': telnet_data[117:122], 'frequency_offset': float(telnet_data[123:129]), 'signal_quality': float(telnet_data[132:137]), 'error_count': float(telnet_data[139:142]), 'distance': float(telnet_data[143:150]), 'bearing': float(telnet_data[152:158]), 'phi': float(telnet_data[161:167])} except: raise ParseError
def parse(telnet_data): reference_timestamp = datetime.utcnow() match = telnet_50001_pattern.match(telnet_data) if match: return {'pps_offset': float(match.group('pps_offset')), 'frequency': float(match.group('frequency')), 'aircraft_type': int(match.group('aircraft_type')), 'address_type': int(match.group('address_type')), 'address': match.group('address'), 'timestamp': createTimestamp(match.group('timestamp') + 'h', reference_timestamp), 'latitude': float(match.group('latitude')), 'longitude': float(match.group('longitude')), 'altitude': int(match.group('altitude')), 'climb_rate': float(match.group('climb_rate')), 'ground_speed': float(match.group('ground_speed')), 'track': float(match.group('track')), 'turn_rate': float(match.group('turn_rate')), 'magic_number': int(match.group('magic_number')), 'gps_status': match.group('gps_status'), 'channel': int(match.group('channel')), 'flarm_timeslot': match.group('flarm_timeslot') == 'f', 'ogn_timeslot': match.group('ogn_timeslot') == 'o', 'frequency_offset': float(match.group('frequency_offset')), 'decode_quality': float(match.group('decode_quality')), 'signal_quality': float(match.group('signal_quality')), 'demodulator_type': int(match.group('demodulator_type')), 'error_count': float(match.group('error_count')), 'distance': float(match.group('distance')), 'bearing': float(match.group('bearing')), 'phi': float(match.group('phi')), 'multichannel': match.group('multichannel') == '+'} else: return None
def test_createTimestamp(self): test_data = [ ('000001', datetime(2015, 1, 10, 0, 0, 1), datetime(2015, 1, 10, 0, 0, 1)), # packet from current day (on the tick) ('235959', datetime(2015, 1, 10, 0, 0, 1), datetime(2015, 1, 9, 23, 59, 59)), # packet from previous day (2 seconds old) ('110000', datetime(2015, 1, 10, 0, 0, 1), None), # packet 11 hours from future or 13 hours old ('123500', datetime(2015, 1, 10, 23, 50, 0), datetime(2015, 1, 10, 12, 35, 0)), # packet from current day (11 hours old) ('000001', datetime(2015, 1, 10, 23, 50, 0), datetime(2015, 1, 11, 0, 0, 1)) # packet from next day (11 minutes from future) ] for test in test_data: if test[2]: timestamp = createTimestamp(test[0], reference=test[1]) self.assertEqual(timestamp, test[2]) else: with self.assertRaises(AmbigousTimeError): createTimestamp(test[0], reference=test[1])
def parse(telnet_data): reference_timestamp = datetime.utcnow() try: return { 'pps_offset': float(telnet_data[0:5]), 'frequency': float(telnet_data[9:16]), 'aircraft_type': int(telnet_data[20:24]), 'address_type': int(telnet_data[25]), 'address': telnet_data[27:33], 'timestamp': createTimestamp(telnet_data[34:40] + 'h', reference_timestamp), 'latitude': float(telnet_data[43:53]), 'longitude': float(telnet_data[54:64]), 'altitude': int(telnet_data[68:73]), 'climb_rate': float(telnet_data[74:80]), 'ground_speed': float(telnet_data[83:89]), 'track': float(telnet_data[92:98]), 'turn_rate': float(telnet_data[101:107]), 'magic_number': int(telnet_data[114:116]), 'gps_status': telnet_data[117:122], 'frequency_offset': float(telnet_data[123:129]), 'signal_quality': float(telnet_data[132:137]), 'error_count': float(telnet_data[139:142]), 'distance': float(telnet_data[143:150]), 'bearing': float(telnet_data[152:158]), 'phi': float(telnet_data[161:167]) } except: raise ParseError
def parse_aprs(message, reference_date=None): if reference_date is None: reference_date = datetime.utcnow() match = re.search(PATTERN_APRS, message) if match: return { 'name': match.group('callsign'), 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match.group('time'), reference_date), 'latitude': dmsToDeg(float(match.group('latitude')) / 100) * (-1 if match.group('latitude_sign') == 'S' else 1) + (int(match.group('latitude_enhancement')) / 1000 / 60 if match.group('latitude_enhancement') else 0), 'symboltable': match.group('symbol_table'), 'longitude': dmsToDeg(float(match.group('longitude')) / 100) * (-1 if match.group('longitude_sign') == 'W' else 1) + (int(match.group('longitude_enhancement')) / 1000 / 60 if match.group('longitude_enhancement') else 0), 'symbolcode': match.group('symbol'), 'track': int(match.group('course')) if match.group('course_extension') else 0, 'ground_speed': int(match.group('ground_speed')) * kts2kmh if match.group('ground_speed') else 0, 'altitude': int(match.group('altitude')) * feet2m, 'comment': match.group('comment') } raise AprsParseError(message)
def parse_aprs(message, reference_date=None): if reference_date is None: reference_date = datetime.utcnow() match = re.search(PATTERN_APRS, message) if match: return {'name': match.group('callsign'), 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match.group('time'), reference_date), 'latitude': dmsToDeg(float(match.group('latitude')) / 100) * (-1 if match.group('latitude_sign') == 'S' else 1) + (int(match.group('latitude_enhancement')) / 1000 / 60 if match.group('latitude_enhancement') else 0), 'symboltable': match.group('symbol_table'), 'longitude': dmsToDeg(float(match.group('longitude')) / 100) * (-1 if match.group('longitude_sign') == 'W' else 1) + (int(match.group('longitude_enhancement')) / 1000 / 60 if match.group('longitude_enhancement') else 0), 'symbolcode': match.group('symbol'), 'track': int(match.group('course')) if match.group('course_extension') else 0, 'ground_speed': int(match.group('ground_speed')) * kts2kmh if match.group('ground_speed') else 0, 'altitude': int(match.group('altitude')) * feet2m, 'comment': match.group('comment')} raise AprsParseError(message)
def parse_aprs(message, reference_timestamp=None): if reference_timestamp is None: reference_timestamp = datetime.utcnow() result = { 'raw_message': message, 'reference_timestamp': reference_timestamp } if message and message[0] == '#': match_server = re.search(PATTERN_SERVER, message) if match_server: 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' }) else: result.update({'comment': message, 'aprs_type': 'comment'}) else: match = re.search(PATTERN_APRS, message) if match: aprs_type = 'position' if match.group( 'aprs_type') == '/' else 'status' if match.group( 'aprs_type') == '>' else 'unknown' 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'), 'dstcall': match.group('dstcall'), 'relay': match.group('relay') if match.group('relay') else None, 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match_position.group('time'), reference_timestamp), 'latitude': parseAngle('0' + match_position.group('latitude') + (match_position.group( 'latitude_enhancement') or '0')) * # noqa: W504 (-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')) * # noqa: W504 (-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, '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 if match_position.group('altitude') else None, 'aircrafttype': get_aircraft_type(match_position.group('symbol_table'), match_position.group('symbol')), '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'), 'dstcall': match.group('dstcall'), 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match_status.group('time'), reference_timestamp), 'comment': match_status.group('comment') if match_status.group('comment') else "" }) else: raise NotImplementedError(message) else: raise AprsParseError(message) return result
def proceed_test_data(self, test_data={}): for test in test_data: timestamp = createTimestamp(test[0], reference_timestamp=test[1]) self.assertEqual(timestamp, test[2])
def parse_aprs(message, reference_timestamp=None): if reference_timestamp is None: reference_timestamp = datetime.utcnow() result = { 'raw_message': message, 'reference_timestamp': reference_timestamp } if message and message[0] == '#': match_server = re.search(PATTERN_SERVER, message) if match_server: 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' }) else: result.update({'comment': message, 'aprs_type': 'comment'}) else: match = re.search(PATTERN_APRS, message) if match: aprs_type = 'position' if match.group( 'aprs_type') == '/' else 'status' if match.group( 'aprs_type') == '>' else 'unknown' 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'), 'dstcall': match.group('dstcall'), 'relay': match.group('relay') if match.group('relay') else None, 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match_position.group('time'), reference_timestamp), 'latitude': parseAngle('0' + match_position.group('latitude') + (match_position.group( 'latitude_enhancement') or '0')) * # noqa: W504 (-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')) * # noqa: W504 (-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, '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 if match_position.group('altitude') else None, 'comment': match_position.group('comment') if match_position.group('comment') else "", }) return result match_position_weather = re.search( PATTERN_APRS_POSITION_WEATHER, aprs_body) if match_position_weather: result.update({ 'aprs_type': 'position_weather', 'name': match.group('callsign'), 'dstcall': match.group('dstcall'), 'relay': match.group('relay') if match.group('relay') else None, 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match_position_weather.group('time'), reference_timestamp), 'latitude': parseAngle('0' + match_position_weather.group('latitude')) * # noqa: W504 (-1 if match_position_weather.group('latitude_sign') == 'S' else 1), 'symboltable': match_position_weather.group('symbol_table'), 'longitude': parseAngle(match_position_weather.group('longitude')) * # noqa: W504 (-1 if match_position_weather.group('longitude_sign') == 'W' else 1), 'symbolcode': match_position_weather.group('symbol'), 'wind_direction': int(match_position_weather.group('wind_direction')) if match_position_weather.group('wind_direction') != '...' else None, 'wind_speed': int(match_position_weather.group('wind_speed')) * KNOTS_TO_MS / KPH_TO_MS if match_position_weather.group('wind_speed') != '...' else None, 'wind_speed_peak': int(match_position_weather.group('wind_speed_peak')) * KNOTS_TO_MS / KPH_TO_MS if match_position_weather.group('wind_speed_peak') != '...' else None, 'temperature': fahrenheit_to_celsius( float(match_position_weather.group('temperature'))) if match_position_weather.group('temperature') != '...' else None, 'rainfall_1h': int(match_position_weather.group('rainfall_1h')) / 100.0 * INCH_TO_MM if match_position_weather.group('rainfall_1h') else None, 'rainfall_24h': int(match_position_weather.group('rainfall_24h')) / 100.0 * INCH_TO_MM if match_position_weather.group('rainfall_24h') else None, 'humidity': int(match_position_weather.group('humidity')) * 0.01 if match_position_weather.group('humidity') else None, 'barometric_pressure': int(match_position_weather.group( 'barometric_pressure')) if match_position_weather.group('barometric_pressure') else None, 'comment': match_position_weather.group('comment') if match_position_weather.group('comment') else "", }) return result 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'), 'dstcall': match.group('dstcall'), 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match_status.group('time'), reference_timestamp), 'comment': match_status.group('comment') if match_status.group('comment') else "" }) else: raise NotImplementedError(message) else: raise AprsParseError(message) return result
def parse_aprs(message, reference_timestamp=None): if reference_timestamp is None: reference_timestamp = datetime.utcnow() result = {'raw_message': message, 'reference_timestamp': reference_timestamp} if message and message[0] == '#': match_server = re.search(PATTERN_SERVER, message) if match_server: 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'}) else: result.update({ 'comment': message, 'aprs_type': 'comment'}) 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'), 'dstcall': match.group('dstcall'), 'relay': match.group('relay') if match.group('relay') else None, 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match_position.group('time'), reference_timestamp), '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, '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, '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'), 'dstcall': match.group('dstcall'), 'receiver_name': match.group('receiver'), 'timestamp': createTimestamp(match_status.group('time'), reference_timestamp), 'comment': match_status.group('comment') if match_status.group('comment') else ""}) else: raise AprsParseError(message) else: raise AprsParseError(message) return result