parent
2b139d1857
commit
2a27dc4416
|
|
@ -136,17 +136,24 @@ def parse_data_extentions(body):
|
||||||
parsed = {}
|
parsed = {}
|
||||||
|
|
||||||
# course speed bearing nrq
|
# course speed bearing nrq
|
||||||
|
# Page 27 of the spec
|
||||||
# format: 111/222/333/444text
|
# format: 111/222/333/444text
|
||||||
match = re.findall(r"^([0-9 .]{3})/([0-9 .]{3})", body)
|
match = re.findall(r"^([0-9 \.]{3})/([0-9 \.]{3})", body)
|
||||||
if match:
|
if match:
|
||||||
cse, spd = match[0]
|
cse, spd = match[0]
|
||||||
body = body[7:]
|
body = body[7:]
|
||||||
parsed.update({'course': int(cse) if cse.isdigit() and 1 <= int(cse) <= 360 else 0})
|
if cse.isdigit() and cse != "000":
|
||||||
if spd.isdigit():
|
parsed.update({'course': int(cse) if 1 <= int(cse) <= 360 else 0})
|
||||||
|
if spd.isdigit() and spd != "000":
|
||||||
parsed.update({'speed': int(spd)*1.852})
|
parsed.update({'speed': int(spd)*1.852})
|
||||||
|
|
||||||
match = re.findall(r"^/([0-9 .]{3})/([0-9 .]{3})", body)
|
# DF Report format
|
||||||
|
# Page 29 of teh spec
|
||||||
|
match = re.findall(r"^/([0-9 \.]{3})/([0-9 \.]{3})", body)
|
||||||
if match:
|
if match:
|
||||||
|
# cse=000 means stations is fixed, Page 29 of the spec
|
||||||
|
if cse == '000':
|
||||||
|
parsed.update({'course': 0})
|
||||||
brg, nrq = match[0]
|
brg, nrq = match[0]
|
||||||
body = body[8:]
|
body = body[8:]
|
||||||
if brg.isdigit():
|
if brg.isdigit():
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import re
|
||||||
from aprslib import base91
|
from aprslib import base91
|
||||||
from aprslib.exceptions import ParseError
|
from aprslib.exceptions import ParseError
|
||||||
from aprslib.parsing import logger
|
from aprslib.parsing import logger
|
||||||
from aprslib.parsing.common import parse_timestamp, parse_comment
|
from aprslib.parsing.common import parse_timestamp, parse_comment, parse_data_extentions
|
||||||
from aprslib.parsing.weather import parse_weather_data
|
from aprslib.parsing.weather import parse_weather_data
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
|
@ -60,6 +60,11 @@ def parse_position(packet_type, body):
|
||||||
# check comment for weather information
|
# check comment for weather information
|
||||||
# Page 62 of the spec
|
# Page 62 of the spec
|
||||||
if parsed['symbol'] == '_':
|
if parsed['symbol'] == '_':
|
||||||
|
# attempt to parse winddir/speed
|
||||||
|
# Page 92 of the spec
|
||||||
|
body, result = parse_data_extentions(body)
|
||||||
|
parsed.update(result)
|
||||||
|
|
||||||
logger.debug("Attempting to parse weather report from comment")
|
logger.debug("Attempting to parse weather report from comment")
|
||||||
body, result = parse_weather_data(body)
|
body, result = parse_weather_data(body)
|
||||||
parsed.update({
|
parsed.update({
|
||||||
|
|
|
||||||
|
|
@ -256,30 +256,47 @@ class DataExtentionsTC(unittest.TestCase):
|
||||||
'speed': 100*1.852,
|
'speed': 100*1.852,
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_empty_course_speed(self):
|
def test_course_speed_spaces(self):
|
||||||
body = " / /text"
|
body = " / /text"
|
||||||
remaining, parsed = parse_data_extentions(body)
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
||||||
self.assertEqual(remaining, '/text')
|
self.assertEqual(remaining, '/text')
|
||||||
self.assertEqual(parsed, {
|
self.assertEqual(parsed, {})
|
||||||
'course': 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
def test_course_speed_dots(self):
|
||||||
body = ".../.../text"
|
body = ".../.../text"
|
||||||
remaining, parsed = parse_data_extentions(body)
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
||||||
self.assertEqual(remaining, '/text')
|
self.assertEqual(remaining, '/text')
|
||||||
self.assertEqual(parsed, {
|
self.assertEqual(parsed, {})
|
||||||
'course': 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
def test_course_speed_zeros(self):
|
||||||
|
body = "000/000/text"
|
||||||
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
||||||
|
self.assertEqual(remaining, '/text')
|
||||||
|
self.assertEqual(parsed, {})
|
||||||
|
|
||||||
|
def test_course_speed_valid_chars_but_invalid_values(self):
|
||||||
body = "22./33 /text"
|
body = "22./33 /text"
|
||||||
remaining, parsed = parse_data_extentions(body)
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
||||||
self.assertEqual(remaining, '/text')
|
self.assertEqual(remaining, '/text')
|
||||||
self.assertEqual(parsed, {
|
self.assertEqual(parsed, {})
|
||||||
'course': 0,
|
|
||||||
})
|
def test_course_speed_invalid_chars_spd(self):
|
||||||
|
body = "222/33a/text"
|
||||||
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
||||||
|
self.assertEqual(remaining, '222/33a/text')
|
||||||
|
self.assertEqual(parsed, {})
|
||||||
|
|
||||||
|
def test_course_speed_invalid_chars_cse(self):
|
||||||
|
body = "22a/333/text"
|
||||||
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
||||||
|
self.assertEqual(remaining, '22a/333/text')
|
||||||
|
self.assertEqual(parsed, {})
|
||||||
|
|
||||||
def test_empty_bearing_nrq(self):
|
def test_empty_bearing_nrq(self):
|
||||||
body = "111/100/ /...text"
|
body = "111/100/ /...text"
|
||||||
|
|
@ -300,6 +317,17 @@ class DataExtentionsTC(unittest.TestCase):
|
||||||
'speed': 100*1.852,
|
'speed': 100*1.852,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_course_speed_bearing_nrq_empty_cse_speed(self):
|
||||||
|
body = "000/000/234/345text"
|
||||||
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
||||||
|
self.assertEqual(remaining, 'text')
|
||||||
|
self.assertEqual(parsed, {
|
||||||
|
'course': 0,
|
||||||
|
'bearing': 234,
|
||||||
|
'nrq': 345,
|
||||||
|
})
|
||||||
|
|
||||||
def test_course_speed_bearing_nrq(self):
|
def test_course_speed_bearing_nrq(self):
|
||||||
body = "123/100/234/345text"
|
body = "123/100/234/345text"
|
||||||
remaining, parsed = parse_data_extentions(body)
|
remaining, parsed = parse_data_extentions(body)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from aprslib.parsing import parse_position
|
||||||
|
|
||||||
|
wind_multiplier = 0.44704
|
||||||
|
mm_multiplier = 0.254
|
||||||
|
|
||||||
|
class ParsePositionDataExtAndWeather(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.maxDiff = None
|
||||||
|
|
||||||
|
def test_position_packet_only_weather_valid(self):
|
||||||
|
packet_type = '@'
|
||||||
|
packet = "092345z4903.50N/07201.75W_g000t066r000p000...dUII"
|
||||||
|
expected = {
|
||||||
|
'messagecapable': True,
|
||||||
|
'raw_timestamp': '092345z',
|
||||||
|
'timestamp': 1657410300,
|
||||||
|
'format': 'uncompressed',
|
||||||
|
'posambiguity': 0,
|
||||||
|
'symbol': '_',
|
||||||
|
'symbol_table': '/',
|
||||||
|
'latitude': 49.05833333333333,
|
||||||
|
'longitude': -72.02916666666667,
|
||||||
|
'comment': '...dUII',
|
||||||
|
'weather': {
|
||||||
|
'wind_gust': 0.0,
|
||||||
|
'temperature': 18.88888888888889,
|
||||||
|
'rain_1h': 0.0,
|
||||||
|
'rain_24h': 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result = parse_position(packet_type, packet)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_position_packet_data_ext_and_weather_valid(self):
|
||||||
|
packet_type = '@'
|
||||||
|
packet = "092345z4903.50N/07201.75W_090/001g000t066r000p000...dUII"
|
||||||
|
expected = {
|
||||||
|
'messagecapable': True,
|
||||||
|
'raw_timestamp': '092345z',
|
||||||
|
'timestamp': 1657410300,
|
||||||
|
'format': 'uncompressed',
|
||||||
|
'posambiguity': 0,
|
||||||
|
'symbol': '_',
|
||||||
|
'symbol_table': '/',
|
||||||
|
'latitude': 49.05833333333333,
|
||||||
|
'longitude': -72.02916666666667,
|
||||||
|
'course': 90,
|
||||||
|
'speed': 1*1.852,
|
||||||
|
'comment': '...dUII',
|
||||||
|
'weather': {
|
||||||
|
'wind_gust': 0.0,
|
||||||
|
'temperature': 18.88888888888889,
|
||||||
|
'rain_1h': 0.0,
|
||||||
|
'rain_24h': 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result = parse_position(packet_type, packet)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_position_packet_optional_speed(self):
|
||||||
|
packet_type = '@'
|
||||||
|
packet = "092345z4903.50N/07201.75W_090/...g000t066r000p000...dUII"
|
||||||
|
expected = {
|
||||||
|
'messagecapable': True,
|
||||||
|
'raw_timestamp': '092345z',
|
||||||
|
'timestamp': 1657410300,
|
||||||
|
'format': 'uncompressed',
|
||||||
|
'posambiguity': 0,
|
||||||
|
'symbol': '_',
|
||||||
|
'symbol_table': '/',
|
||||||
|
'latitude': 49.05833333333333,
|
||||||
|
'longitude': -72.02916666666667,
|
||||||
|
'course': 90,
|
||||||
|
'comment': '...dUII',
|
||||||
|
'weather': {
|
||||||
|
'wind_gust': 0.0,
|
||||||
|
'temperature': 18.88888888888889,
|
||||||
|
'rain_1h': 0.0,
|
||||||
|
'rain_24h': 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result = parse_position(packet_type, packet)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_position_packet_optional_course(self):
|
||||||
|
packet_type = '@'
|
||||||
|
packet = "092345z4903.50N/07201.75W_ /001g000t066r000p000...dUII"
|
||||||
|
expected = {
|
||||||
|
'messagecapable': True,
|
||||||
|
'raw_timestamp': '092345z',
|
||||||
|
'timestamp': 1657410300,
|
||||||
|
'format': 'uncompressed',
|
||||||
|
'posambiguity': 0,
|
||||||
|
'symbol': '_',
|
||||||
|
'symbol_table': '/',
|
||||||
|
'latitude': 49.05833333333333,
|
||||||
|
'longitude': -72.02916666666667,
|
||||||
|
'speed': 1*1.852,
|
||||||
|
'comment': '...dUII',
|
||||||
|
'weather': {
|
||||||
|
'wind_gust': 0.0,
|
||||||
|
'temperature': 18.88888888888889,
|
||||||
|
'rain_1h': 0.0,
|
||||||
|
'rain_24h': 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result = parse_position(packet_type, packet)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_position_packet_optional_speed_and_course(self):
|
||||||
|
packet_type = '@'
|
||||||
|
packet = "092345z4903.50N/07201.75W_.../...g000t066r000p000...dUII"
|
||||||
|
expected = {
|
||||||
|
'messagecapable': True,
|
||||||
|
'raw_timestamp': '092345z',
|
||||||
|
'timestamp': 1657410300,
|
||||||
|
'format': 'uncompressed',
|
||||||
|
'posambiguity': 0,
|
||||||
|
'symbol': '_',
|
||||||
|
'symbol_table': '/',
|
||||||
|
'latitude': 49.05833333333333,
|
||||||
|
'longitude': -72.02916666666667,
|
||||||
|
'comment': '...dUII',
|
||||||
|
'weather': {
|
||||||
|
'wind_gust': 0.0,
|
||||||
|
'temperature': 18.88888888888889,
|
||||||
|
'rain_1h': 0.0,
|
||||||
|
'rain_24h': 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result = parse_position(packet_type, packet)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
def test_position_packet_optional_course(self):
|
||||||
|
packet_type = '@'
|
||||||
|
packet = "092345z4903.50N/07201.75W_ /001g000t066r000p000...dUII"
|
||||||
|
expected = {
|
||||||
|
'messagecapable': True,
|
||||||
|
'raw_timestamp': '092345z',
|
||||||
|
'timestamp': 1657410300,
|
||||||
|
'format': 'uncompressed',
|
||||||
|
'posambiguity': 0,
|
||||||
|
'symbol': '_',
|
||||||
|
'symbol_table': '/',
|
||||||
|
'latitude': 49.05833333333333,
|
||||||
|
'longitude': -72.02916666666667,
|
||||||
|
'speed': 1*1.852,
|
||||||
|
'comment': '...dUII',
|
||||||
|
'weather': {
|
||||||
|
'wind_gust': 0.0,
|
||||||
|
'temperature': 18.88888888888889,
|
||||||
|
'rain_1h': 0.0,
|
||||||
|
'rain_24h': 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result = parse_position(packet_type, packet)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Loading…
Reference in New Issue