diff --git a/aprs.py b/aprs.py index 79aa35a..d11bd8d 100644 --- a/aprs.py +++ b/aprs.py @@ -10,6 +10,8 @@ from datetime import datetime import kiss import aprslib +import pick_pretty_description from aprs_to_callsign + MYCALL = os.environ.get("MYCALL", "N0CALL") KISS_HOST = os.environ.get("KISS_HOST", "10.10.10.91") KISS_PORT = os.environ.get("KISS_PORT", "8001") @@ -28,7 +30,7 @@ def parse_frame(date, frame): except (aprslib.ParseError, aprslib.UnknownFormat) as exp: logger.error(f"Failed to parse frame: {frame}") return str(frame) - formatted_string = date.strftime('%H:%M:%S.%f')[:-3] + " " + "{} -> {} -> {}:".format(parsed["from"], parsed["via"], parsed["to"]) + formatted_string = date.strftime('%H:%M:%S.%f')[:-3] + " " + "{} -> {} -> {}:".format(parsed["from"], parsed["via"], pick_pretty_description(parsed["to"]))) formatted_string += " <{:.4f} {:.4f}>".format(parsed["latitude"], parsed["longitude"]) if "longitude" in parsed and "latitude" in parsed else "" formatted_string += " tUNIT: " + ",".join(parsed["tUNIT"]) if "tUNIT" in parsed else "" formatted_string += " tPARM: " + ",".join(parsed["tPARM"]) if "tPARM" in parsed else "" diff --git a/aprs_to_callsign.py b/aprs_to_callsign.py new file mode 100644 index 0000000..1bdae47 --- /dev/null +++ b/aprs_to_callsign.py @@ -0,0 +1,171 @@ +# source: http://aprs.org/aprs11/tocalls.txt +ALTNET_DESCRIPTION = 'An ALTNET is defined to be ANY AX.25 TOCALL that is NOT one of the normal APRS TOCALL' + +TOCALLS = { + # slightly trasformed table from the source + 'AP1WWX': 'TAPR T-238+ WX station', + 'AP4Ry': 'APRS4R software interface', + 'APnnnD': 'Painter Engineering uSmartDigi D-Gate DSTAR Gateway', + 'APnnnU': 'Painter Engineering uSmartDigi Digipeater', + 'APAF': 'AFilter.', + 'APAG': 'AGATE', + 'APAGW': "SV2AGW's AGWtracker", + 'APA': 'AFilterX.', + 'APAH': 'AHub', + 'APAND1': 'APRSdroid (replaced by APDRxx', + 'APAW': 'AGWPE', + 'APB': 'Beacons or Rabbit TCPIP micros?', + 'APBL': 'BigRedBee BeeLine', + 'APBLO': 'MOdel Rocketry K7RKT', + 'APC': 'Cellular applications', + 'APCBB': 'for VE7UDP Blackberry Applications', + 'APCLEY': 'EYTraker GPRS/GSM tracker by ZS6EY', + 'APCLW': 'EYWeather GPRS/GSM WX station by ZS6EY', + 'APCLEZ': 'Telit EZ10 GSM application ZS6CEY', + 'APCY': 'Cybiko applications', + 'APRSd': 'etc', + 'APD4': 'UP4DAR platform', + 'APDD': 'DV-RPTR Modem and Control Center Software', + 'APDF': 'Automatic DF units', + 'APDG': 'D-Star Gateways by G4KLX ircDDB', + 'APDH': 'WinDV (DUTCH*Star DV Node for Windows)', + 'APDInn': 'DIXPRS - Bela, HA5DI', + 'APDK': 'KI4LKF g2_ircddb Dstar gateway software', + 'APDO': 'ON8JL Standalone DStar Node', + 'APDPRS': 'D-Star originated posits', + 'APDR': 'APrsDRoid replaces old APAND1.', + 'APDS': 'SP9UOB for dsDigi and ds-tracker', + 'APDT': 'APRStouch Tone (DTMF)', + 'APDU': 'U2APRS by JA7UDE', + 'APDW': 'DireWolf, WB2OSZ', + 'APE': 'Telemetry devices', + 'APERQ': 'Experimental tracker by PE1RXQ', + 'APF': 'Firenet', + 'APFG': 'Flood Gage (KP4DJT)', + 'APG': 'Gates, etc', + 'APGO': 'for AA3NJ PDA application', + 'APH': 'HamHud, etc', + 'APHK': 'for LA1BR tracker/digipeater', + 'API': 'Icom, etc', + 'APICQ': 'for ICQ', + 'APJA': 'JavAPRS', + 'APJE': 'JeAPRS', + 'APJI': 'jAPRSIgate', + 'APJS': 'javAPRSSrvr', + 'APK0': "Kenwood TH-D7's", + 'APK003': 'Kenwood TH-D72', + 'APK1': "Kenwood D700's", + 'APR102': 'Kenwood D710', + 'APKRAM': 'KRAMstuff.com - Mark. G7LEU', + 'APL': 'Linux applications', + 'APM': 'MacAPRS, etc', + 'APN': 'Network nodes, digis, etc', + 'APN3': 'Kantronics KPC-3 rom versions', + 'APN9': 'Kantronics KPC-9612 Roms', + 'APNA': "WB6ZSU's APRServe", + 'APND': 'DIGI_NED ssid routing ok', + 'APNM': 'MJF TNC roms', + 'APNP': 'Paccom TNC roms', + 'APNT': "SV2AGW's TNT tnc as a digi", + 'APNU': 'UIdigi; ssid routing ok', + 'APN': 'TNC-X (K6DBG)', + 'APNK01': 'Kenwood D700 (APK101) type', + 'APNK80': 'KAM version 8.0', + 'APNKMP': 'KAM+', + 'APOA': 'OpenAPRS - Greg Carter', + 'APOT': 'OpenTrack', + 'APOD1w': 'OpenTrack with 1 wire WX', + 'APOU2k': 'OpenTrack for Ultimeter', + 'APP': 'pocketAPRS, etc', + 'APPT': 'KetaiTracker by JF6LZE, Takeki (msg capable)', + 'APQ': 'Earthquake data', + 'APR8': 'APRSdos versions 800+', + 'APRD': 'APRSdata, APRSdr', + 'APRG': 'aprsg igate software, OH2GVE', + 'APRHH2': 'HamHud 2', + 'APRK': 'APRStk', + 'APRNOW': 'W5GGW ipad application', + 'APRRT': 'RPC electronics', + 'APRS': 'Generic, (obsolete. Digis should use APNxxx instead)', + 'APR': '>APRSmax 40 ', + 'APR': "OH2MQK's RX-igate <39", + 'APRTLM': "used in MIM's and Mic-lites, etc", + 'APRtfc': 'APRStraffic', + 'APRST': 'APRStt (Touch tone)', + 'APSK63': 'APRS Messenger -over-PSK63', + 'APSK25': 'APRS Messenger GMSK-250', + 'APTIGR': 'TigerTrack', + 'APTT': 'Tiny Track', + 'APT2': 'Tiny Track II', + 'APT3': 'Tiny Track III', + 'APTA': "K4ATM's tiny track", + 'APTW': 'Byons WXTrac', + 'APTV': 'for ATV/APRN and SSTV application', + 'APU1': 'UIview 16 bit applications', + 'APU2': 'UIview 32 bit apps', + 'APU3': 'UIview terminal program', + 'APV': 'VoIP Voice over Internet application', + 'APVR': 'IRLP', + 'APVL': 'I-LINK', + 'APVE': 'ECHO link', + 'APW': 'WinAPRS, etc', + 'APWS': "DF4IAN's WS2300 WX station", + 'APWM': 'APRSISCE KJ4ERJ', + 'APWW': 'APRSISCE win32 version', + 'AP': 'Xastir', + 'APR': 'Xrouter', + 'APY': 'Yeasu', + 'APZ': 'Experimental', + 'APZ0': 'Xastir (old versions. See APX) ssid routing ok', + 'APZMDR': 'HaMDR trackers - hessu * hes.iki.fi' , + 'APZPAD': 'Smart Palm', + 'APZWIT': 'MAP27 radio (Mountain Rescue) EI7IG', +} + +# def filter_by_dest(aprs_destination): +# ''' +# Just a shorthand to filter through the dict +# ''' +# return { key:TOCALLS[key] for key in TOCALLS.keys() if aprs_destination.lower() in key.lower()} + +def search_for_dest(aprs_destination): + i = 2 + filter_by_dest = lambda to_call: { key:TOCALLS[key] for key in TOCALLS.keys() if to_call.lower() in key.lower()} + pick_by_prefix = lambda i: filter_by_dest(aprs_destination[:i]) + results_ammount = lambda i: len(pick_by_prefix(i)) + results = {aprs_destination: ''} + while results_ammount(i) > 0: + if i == 6: + break + i += 1 + if results_ammount(i) == 1: + return pick_by_prefix(i) + else: + return results + +# list(pick_description(parsed["to"]).values())[0] +def pick_description(aprs_destination, filter_altnets=True): + descr = ALTNET_DESCRIPTION if not filter_altnets else '' + match_tocall = lambda x: aprs_destination.lower().startswith(x.lower()) + if not match_tocall('ap'): + # ALL, BEACON, CQ, QST, GPSxxx + if match_tocall('ALL'): + descr = 'ALL' + elif match_tocall('BEACON'): + descr = 'BEACON' + elif match_tocall('CQ'): + descr = 'CQ' + elif match_tocall('QST'): + descr = 'QST' + elif match_tocall('GPS'): + descr = 'GPS' + return {aprs_destination: descr} + else: + return search_for_dest(aprs_destination) + +def pick_pretty_description(aprs_destination, filter_altnets=True): + ''' + For now it's just two first words from description. + ''' + result = pick_description(aprs_destination, filter_altnets) + return ' '.join(list(result.values())[0].split()[:2])