Packet parsing¶
An overview of the parsing functionality.
APRS Reference¶
The implementation follows the APRS Protocol Reference
- Version 1.0: http://www.aprs.org/doc/APRS101.PDF
- Version 1.1: http://www.aprs.org/aprs11.html
- Version 1.2: http://www.aprs.org/aprs12.html
Encodings¶
Packets can often contain characters outside of 7-bit ASCII.
aprslib.parse()
will attempt to guess the charset and return unicode
strings using these steps and in that order:
- Attempt to decode string as
utf-8
- Attempt to guess the charset using
chardet
module (if installed), decode if confidence factor is sufficient - Finally, decode as
latin-1
Supported formats¶
- normal/compressed position reports
- mic-e position reports
- objects reports
- weather reports
- status reports
- messages (inc. telemetry, bulletins, etc)
- base91 comment telemetry extension
- altitude extension
- beacons
Position reports¶
Normal¶
>>> aprslib.parse("FROMCALL>TOCALL:!4903.50N/07201.75W-Test /A=001234")
{'altitude': 376.1232,
'comment': u'Test',
'format': 'uncompressed',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'messagecapable': False,
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:!4903.50N/07201.75W-Test /A=001234',
'symbol': u'-',
'symbol_table': u'/',
'to': u'TOCALL',
'via': ''}
Compressed¶
>>> aprslib.parse("M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@\"v90!+|")
{'altitude': 12450.7752,
'comment': u'Xa',
'format': 'compressed',
'from': u'M0XER-4',
'gpsfixstatus': 1,
'latitude': 64.11987367625208,
'longitude': -19.070654142799384,
'messagecapable': False,
'path': [u'TF3RPF', u'WIDE2*', u'qAR', u'TF3SUT-2'],
'raw': u'M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@"v90!+|',
'symbol': u'O',
'symbol_table': u'/',
'telemetry': {'bits': '00000000',
'seq': 215,
'vals': [2670, 176, 2199, 10, 0]},
'to': u'APRS64',
'via': u'TF3SUT-2'}
With timestamp:
>>> aprslib.parse("FROMCALL>TOCALL:/092345z4903.50N/07201.75W>Test1234")
{'comment': u'Test1234',
'format': 'uncompressed',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'messagecapable': False,
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:/092345z4903.50N/07201.75W>Test1234',
'raw_timestamp': u'092345z',
'symbol': u'>',
'symbol_table': u'/',
'timestamp': 1452383100,
'to': u'TOCALL',
'via': ''}
Mic-E¶
>>> aprslib.parse('FROMCALL>SUSUR1:`CF"l#![/`"3z}_ ')
{'altitude': 8,
'comment': u'`_',
'course': 305,
'format': 'mic-e',
'from': u'FROMCALL',
'latitude': 35.58683333333333,
'longitude': 139.701,
'mbits': u'111',
'mtype': 'M0: Off Duty',
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>SUSUR1:`CF"l#![/`"3z}_ ',
'speed': 0.0,
'symbol': u'[',
'symbol_table': u'/',
'to': u'SUSUR1',
'via': ''}
Objects¶
>>> aprslib.parse('FROMCALL>TOCALL:;LEADER *092345z4903.50N/07201.75W>088/036')
{'alive': True,
'comment': u'',
'course': 88,
'format': 'object',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'object_format': 'uncompressed',
'object_name': u'LEADER ',
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:;LEADER *092345z4903.50N/07201.75W>088/036',
'raw_timestamp': u'092345z',
'speed': 66.672,
'symbol': u'>',
'symbol_table': u'/',
'timestamp': 1452383100,
'to': u'TOCALL',
'via': ''}
Weather¶
Positionless¶
>>> aprslib.parse('FROMCALL>TOCALL:_10090556c220s004g005t077r000p000P000h50b09900wRSW')
{'comment': u'wRSW',
'format': 'wx',
'from': u'FROMCALL',
'path': [],
'raw': u'FROMCALL>TOCALL:_10090556c220s004g005t077r000p000P000h50b09900wRSW',
'to': u'TOCALL',
'via': '',
'weather': {'humidity': 50,
'pressure': 990.0,
'rain_1h': 0.0,
'rain_24h': 0.0,
'rain_since_midnight': 0.0,
'temperature': 25.0,
'wind_direction': 220,
'wind_gust': 2.2352,
'wind_speed': 1.78816},
'wx_raw_timestamp': u'10090556'}
Comment field¶
>>> aprslib.parse("FROMCALL>TOCALL:=4903.50N/07201.75W_225/000g000t050r000p001...h00b10138dU2k")
{'comment': u'...dU2k',
'format': 'uncompressed',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'messagecapable': True,
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:=4903.50N/07201.75W_225/000g000t050r000p001...h00b10138dU2k',
'symbol': u'_',
'symbol_table': u'/',
'to': u'TOCALL',
'via': '',
'weather': {'humidity': 0,
'pressure': 1013.8,
'rain_1h': 0.0,
'rain_24h': 0.254,
'temperature': 10.0,
'wind_direction': 225,
'wind_gust': 0.0,
'wind_speed': 0.0}}
Status report¶
>>> aprslib.parse('FROMCALL>TOCALL:>status text')
{'format': 'status',
'from': u'FROMCALL',
'path': [],
'raw': u'FROMCALL>TOCALL:>status text',
'status': u'status text',
'to': u'TOCALL',
'via': ''}
Messages¶
Regular¶
>>> aprslib.parse('FROMCALL>TOCALL::ADDRCALL :message text')
{'addresse': u'ADDRCALL',
'format': 'message',
'from': u'FROMCALL',
'message_text': u'message text',
'path': [],
'raw': u'FROMCALL>TOCALL::FROMCALL :message text',
'to': u'TOCALL',
'via': ''}
Telemetry configuration¶
>>> aprslib.parse('FROMCALL>TOCALL::FROMCALL :PARM.Vin,Rx1h,Dg1h,Eff1h,A5,O1,O2,O3,O4,I1,I2,I3,I4')
{'addresse': 'FROMCALL',
'format': 'telemetry-message',
'from': 'FROMCALL',
'path': [],
'raw': 'FROMCALL>TOCALL::FROMCALL :PARM.Vin,Rx1h,Dg1h,Eff1h,A5,O1,O2,O3,O4,I1,I2,I3,I4',
'tPARM': ['Vin', 'Rx1h', 'Dg1h', 'Eff1h', 'A5', 'O1', 'O2', 'O3', 'O4', 'I1', 'I2', 'I3', 'I4'],
'to': 'TOCALL',
'via': ''}
>>> aprslib.parse('FROMCALL>TOCALL::FROMCALL :UNIT.Volt,Pkt,Pkt,Pcnt,None,On,On,On,On,Hi,Hi,Hi,Hi')
{'addresse': 'FROMCALL',
'format': 'telemetry-message',
'from': 'FROMCALL',
'path': [],
'raw': 'FROMCALL>TOCALL::FROMCALL :UNIT.Volt,Pkt,Pkt,Pcnt,None,On,On,On,On,Hi,Hi,Hi,Hi',
'tUNIT': ['Volt', 'Pkt', 'Pkt', 'Pcnt', 'None', 'On', 'On', 'On', 'On', 'Hi', 'Hi', 'Hi', 'Hi'],
'to': 'TOCALL',
'via': ''}
>>> aprslib.parse('FROMCALL>TOCALL::FROMCALL :EQNS.0,0.075,0,0,10,0,0,10,0,0,1,0,0,0,0')
{'addresse': 'FROMCALL',
'format': 'telemetry-message',
'from': 'FROMCALL',
'path': [],
'raw': 'FROMCALL>TOCALL::FROMCALL :EQNS.0,0.075,0,0,10,0,0,10,0,0,1,0,0,0,0',
'tEQNS': [[0, 0.075, 0], [0, 10, 0], [0, 10, 0], [0, 1, 0], [0, 0, 0]],
'to': 'TOCALL',
'via': ''}