Skip to content

Commit 9565998

Browse files
committed
Account for telemetry with spaces after commas
Technically invalid, but we should try and parse them anyway as it's just whitespace.
1 parent fb95db6 commit 9565998

File tree

3 files changed

+69
-10
lines changed

3 files changed

+69
-10
lines changed

aprslib/parsing/telemetry.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,23 @@ def parse_telemetry_config(body):
6969
teqns = [0, 1, 0] * 5
7070

7171
for idx, val in enumerate(eqns):
72-
if not re.match(r"^([-]?\d*\.?\d+|)$", val):
72+
# Strip whitespace from values (some packets have spaces after commas)
73+
val = val.strip()
74+
# Extract numeric part if there are non-numeric characters (e.g., "03n" -> "03")
75+
# This handles cases where comments or extra data are concatenated
76+
numeric_match = re.match(r'^([-]?\d*\.?\d+)', val)
77+
if numeric_match:
78+
val = numeric_match.group(1)
79+
elif not re.match(r"^([-]?\d*\.?\d+|)$", val):
7380
raise ParseError("value at %d is not a number in %s" % (idx+1, form))
74-
else:
75-
try:
76-
val = int(val)
77-
except:
78-
val = float(val) if val != "" else 0
7981

80-
teqns[idx] = val
82+
# Convert to number
83+
try:
84+
val = int(val)
85+
except:
86+
val = float(val) if val != "" else 0
87+
88+
teqns[idx] = val
8189

8290
# group values in 5 list of 3
8391
teqns = [teqns[i*3:(i+1)*3] for i in range(5)]
@@ -191,17 +199,28 @@ def parse_telemetry_report(body):
191199

192200
# Parse analog values (can be 000-999, allow decimals and negatives per APRS 1.2)
193201
# Empty values are allowed and treated as 0
202+
# Some packets have data extensions concatenated (e.g., "0>/A=9125")
194203
analog_vals = []
195204
for i, val_str in enumerate(analog_strs):
196205
# Allow empty values (treated as 0)
197206
if not val_str or val_str.strip() == '':
198207
analog_vals.append(0.0)
199208
continue
200209

201-
# Allow integers, decimals, and negative numbers
202-
# Also allow values starting with decimal point (e.g., .10 = 0.10)
203-
if not re.match(r'^-?(\d+\.?\d*|\.\d+)$', val_str):
210+
# Extract numeric part if there are non-numeric characters (e.g., "0>/A=9125" -> "0")
211+
# This handles cases where data extensions are concatenated without proper separation
212+
original_val_str = val_str
213+
numeric_match = re.match(r'^-?(\d+\.?\d*|\.\d+)', val_str)
214+
if numeric_match:
215+
numeric_part = numeric_match.group(0)
216+
remaining = val_str[len(numeric_part):]
217+
val_str = numeric_part
218+
# If there's remaining content (like "/A=9125"), add it to comment
219+
if remaining and not comment:
220+
comment = remaining
221+
elif not re.match(r'^-?(\d+\.?\d*|\.\d+)$', val_str):
204222
raise ParseError("telemetry analog value %d has invalid format" % (i+1))
223+
205224
try:
206225
val = float(val_str)
207226
except ValueError:

tests/test_parse_telemetry.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,20 @@ def test_valid_telemetry_leading_decimal_analog_value(self):
274274
self.assertEqual(result['telemetry']['vals'], [0.1, 12.83, 12.19, 14.0, 14.8])
275275
self.assertEqual(result['telemetry']['bits'], '00000000')
276276

277+
def test_valid_telemetry_analog_value_with_data_extension(self):
278+
"""Test telemetry packet with data extension concatenated to analog value (real-world packet)"""
279+
packet = "IZ1DNG-10>WIDE1-1,WIDE2-2,qAR,IR1UFB:T#8,205,114,170,115,0>/A=9125"
280+
result = parse(packet)
281+
282+
self.assertEqual(result['format'], 'telemetry')
283+
self.assertEqual(result['telemetry']['seq'], 8)
284+
# Analog value 5 is "0>/A=9125" - should extract "0" and preserve "/A=9125" in comment
285+
self.assertEqual(result['telemetry']['vals'], [205.0, 114.0, 170.0, 115.0, 0.0])
286+
self.assertEqual(result['telemetry']['bits'], '00000000')
287+
# The data extension should be preserved in comment
288+
self.assertIn('comment', result)
289+
self.assertIn('/A=9125', result['comment'])
290+
277291
def test_parse_telemetry_report_function_direct(self):
278292
"""Test parse_telemetry_report function directly"""
279293
body = "#123,456,789,012,345,678,11001010,Test"

tests/test_parse_telemetry_config.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,32 @@ def test_parse_telemetry_config_eqns(self):
108108
self.assertIsInstance(result['tEQNS'], list)
109109
self.assertEqual(len(result['tEQNS']), 5)
110110

111+
def test_parse_telemetry_config_eqns_with_spaces(self):
112+
"""Test EQNS telemetry config with spaces after commas (real-world packet)"""
113+
packet = "IZ6RND>IESPX,TCPIP*,qAC,T2NL::IZ6RND :EQNS.0,0.392,-20, 0,0.235,0, 0,0.1,0, 0,1,0, 0,1,0"
114+
result = parse(packet)
115+
116+
self.assertEqual(result['format'], 'telemetry-message')
117+
self.assertIn('tEQNS', result)
118+
self.assertIsInstance(result['tEQNS'], list)
119+
self.assertEqual(len(result['tEQNS']), 5)
120+
# Verify the values are correctly parsed (spaces should be stripped)
121+
expected = [[0, 0.392, -20], [0, 0.235, 0], [0, 0.1, 0], [0, 1, 0], [0, 1, 0]]
122+
self.assertEqual(result['tEQNS'], expected)
123+
124+
def test_parse_telemetry_config_eqns_with_non_numeric_suffix(self):
125+
"""Test EQNS telemetry config with non-numeric characters in last value (real-world packet)"""
126+
packet = "DB0PBG-5>APMI03,DB0OL-10*,WIDE2-1,qAR,DB0PDF-10::DB0PBG-5 :EQNS.0,0.075,0,0,0.5,-64,0,10,0,0,1,0,0,0,03n"
127+
result = parse(packet)
128+
129+
self.assertEqual(result['format'], 'telemetry-message')
130+
self.assertIn('tEQNS', result)
131+
self.assertIsInstance(result['tEQNS'], list)
132+
self.assertEqual(len(result['tEQNS']), 5)
133+
# Verify the values are correctly parsed (03n should be parsed as 3)
134+
expected = [[0, 0.075, 0], [0, 0.5, -64], [0, 10, 0], [0, 1, 0], [0, 0, 3]]
135+
self.assertEqual(result['tEQNS'], expected)
136+
111137
def test_bits_without_binary_bits(self):
112138
"""Test BITS telemetry config without binary bits (malformed packet)"""
113139
packet = "E25HML-13>APRS,TCPIP*,qAC,T2PERTH::E25HML-13:BITS.ESP8266 Test WX DHT22 version"

0 commit comments

Comments
 (0)