Merge pull request #24 from kerel-fs/aprs/+AmbigousTimeError

Add user-defined exception AmbigousTimeError
pull/25/head
Meisterschueler 2015-12-10 21:35:56 +01:00
commit eb738d232c
8 zmienionych plików z 64 dodań i 37 usunięć

Wyświetl plik

@ -1,8 +1,10 @@
from datetime import datetime
from .model import Beacon, AircraftBeacon, ReceiverBeacon from .model import Beacon, AircraftBeacon, ReceiverBeacon
from ogn.exceptions import AprsParseError from ogn.exceptions import AprsParseError
def parse_aprs(packet): def parse_aprs(packet, reference_date=datetime.utcnow()):
if not isinstance(packet, str): if not isinstance(packet, str):
raise TypeError("Expected packet to be str, got %s" % type(packet)) raise TypeError("Expected packet to be str, got %s" % type(packet))
elif packet == "": elif packet == "":
@ -11,7 +13,7 @@ def parse_aprs(packet):
return None return None
beacon = Beacon() beacon = Beacon()
beacon.parse(packet) beacon.parse(packet, reference_date)
# symboltable / symbolcodes used by OGN: # symboltable / symbolcodes used by OGN:
# I&: used as receiver # I&: used as receiver

Wyświetl plik

@ -1,6 +1,8 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
import math import math
from ogn.exceptions import AmbigousTimeError
kmh2kts = 0.539957 kmh2kts = 0.539957
feet2m = 0.3048 feet2m = 0.3048
@ -18,18 +20,19 @@ def dmsToDeg(dms):
return d + m return d + m
def createTimestamp(hhmmss, reference=datetime.utcnow(), validate=False): def createTimestamp(hhmmss, reference):
hh = int(hhmmss[0:2]) packet_time = datetime.strptime(hhmmss, '%H%M%S').time()
mm = int(hhmmss[2:4]) timestamp = datetime.combine(reference, packet_time)
ss = int(hhmmss[4:6])
if (reference.hour == 23) & (hh == 0): if reference.hour == 23 and timestamp.hour == 0:
reference = reference + timedelta(days=1) timestamp = timestamp + timedelta(days=1)
elif (reference.hour == 0) & (hh == 23): elif reference.hour == 0 and timestamp.hour == 23:
reference = reference - timedelta(days=1) timestamp = timestamp - timedelta(days=1)
elif validate and abs(reference.hour - hh) > 1:
raise Exception("Time difference is too big. Reference time:%s - timestamp:%s" % (reference, hhmmss)) if reference - timestamp > timedelta(hours=1):
return datetime(reference.year, reference.month, reference.day, hh, mm, ss) raise AmbigousTimeError(reference, packet_time)
return timestamp
def create_aprs_login(user_name, pass_code, app_name, app_version, aprs_filter=None): def create_aprs_login(user_name, pass_code, app_name, app_version, aprs_filter=None):

Wyświetl plik

@ -1,20 +1,34 @@
""" """
exception definitions exception definitions
""" """
from datetime import datetime
class AprsParseError(Exception): class AprsParseError(Exception):
"""Parse error while parsing an aprs packet.""" """Parse error while parsing an aprs packet."""
def __init__(self, aprs_string): def __init__(self, aprs_string):
self.message = "This is not a valid APRS string: %s" % aprs_string
super(AprsParseError, self).__init__(self.message)
self.aprs_string = aprs_string self.aprs_string = aprs_string
self.message = "This is not a valid APRS string: {}".format(aprs_string)
super(AprsParseError, self).__init__(self.message)
class OgnParseError(Exception): class OgnParseError(Exception):
"""Parse error while parsing an aprs packet substring""" """Parse error while parsing an aprs packet substring."""
def __init__(self, substring, expected_type): def __init__(self, substring, expected_type):
self.message = "For type %s this is not a valid token: %s" % (expected_type, substring)
super(OgnParseError, self).__init__(self.message)
self.substring = substring self.substring = substring
self.expected_type = expected_type self.expected_type = expected_type
self.message = "For type {} this is not a valid token: {}".format(expected_type, substring)
super(OgnParseError, self).__init__(self.message)
class AmbigousTimeError(Exception):
"""Timstamp from the past/future, can't fully reconstruct datetime from timestamp."""
def __init__(self, reference, packet_time):
self.reference = reference
self.packet_time = packet_time
self.timedelta = reference - datetime.combine(reference, packet_time)
self.message = "Can't reconstruct timstamp, {:.0f}s from past.".format(self.timedelta.total_seconds())
super(AmbigousTimeError, self).__init__(self.message)

Wyświetl plik

@ -5,7 +5,7 @@ from time import time
from ogn.gateway import settings from ogn.gateway import settings
from ogn.aprs_parser import parse_aprs from ogn.aprs_parser import parse_aprs
from ogn.aprs_utils import create_aprs_login from ogn.aprs_utils import create_aprs_login
from ogn.exceptions import AprsParseError, OgnParseError from ogn.exceptions import AprsParseError, OgnParseError, AmbigousTimeError
class ognGateway: class ognGateway:
@ -83,6 +83,9 @@ class ognGateway:
except OgnParseError: except OgnParseError:
self.logger.error('OgnParseError while parsing line: {}'.format(line), exc_info=True) self.logger.error('OgnParseError while parsing line: {}'.format(line), exc_info=True)
return return
except AmbigousTimeError as e:
self.logger.error('Drop packet, {:.0f}s from past.'.format(e.timedelta.total_seconds()))
return
if beacon is not None: if beacon is not None:
self.process_beacon(beacon) self.process_beacon(beacon)

Wyświetl plik

@ -1,4 +1,5 @@
import re import re
from datetime import datetime
from sqlalchemy import Column, String, Integer, Float, DateTime from sqlalchemy import Column, String, Integer, Float, DateTime
from sqlalchemy.ext.declarative import AbstractConcreteBase from sqlalchemy.ext.declarative import AbstractConcreteBase
@ -29,7 +30,7 @@ class Beacon(AbstractConcreteBase, Base):
altitude = Column(Integer) altitude = Column(Integer)
comment = None comment = None
def parse(self, text): def parse(self, text, reference_date=datetime.utcnow()):
result = re_pattern_aprs.match(text) result = re_pattern_aprs.match(text)
if result is None: if result is None:
raise AprsParseError(text) raise AprsParseError(text)
@ -37,7 +38,7 @@ class Beacon(AbstractConcreteBase, Base):
self.name = result.group(1) self.name = result.group(1)
self.receiver_name = result.group(2) self.receiver_name = result.group(2)
self.timestamp = createTimestamp(result.group(3)) self.timestamp = createTimestamp(result.group(3), reference_date)
self.latitude = dmsToDeg(float(result.group(4)) / 100) self.latitude = dmsToDeg(float(result.group(4)) / 100)
if result.group(5) == "S": if result.group(5) == "S":

Wyświetl plik

@ -1,4 +1,5 @@
import unittest import unittest
from datetime import datetime
from ogn.aprs_parser import parse_aprs from ogn.aprs_parser import parse_aprs
from ogn.exceptions import AprsParseError, OgnParseError from ogn.exceptions import AprsParseError, OgnParseError
@ -8,7 +9,7 @@ class TestStringMethods(unittest.TestCase):
def test_valid_beacons(self): def test_valid_beacons(self):
with open('tests/valid_beacons.txt') as f: with open('tests/valid_beacons.txt') as f:
for line in f: for line in f:
parse_aprs(line) parse_aprs(line, datetime(2015, 4, 10, 17, 0))
def test_fail_none(self): def test_fail_none(self):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
@ -24,11 +25,13 @@ class TestStringMethods(unittest.TestCase):
def test_incomplete_device_string(self): def test_incomplete_device_string(self):
with self.assertRaises(OgnParseError): with self.assertRaises(OgnParseError):
parse_aprs("ICA4B0E3A>APRS,qAS,Letzi:/072319h4711.75N\\00802.59E^327/149/A=006498 id154B0E3A -395") parse_aprs("ICA4B0E3A>APRS,qAS,Letzi:/072319h4711.75N\\00802.59E^327/149/A=006498 id154B0E3A -395",
datetime(2015, 4, 10, 7, 24))
def test_incomplete_receiver_string(self): def test_incomplete_receiver_string(self):
with self.assertRaises(OgnParseError): with self.assertRaises(OgnParseError):
parse_aprs("Lachens>APRS,TCPIP*,qAC,GLIDERN2:/165334h4344.70NI00639.19E&/A=005435 v0.2.1 CPU:0.3 RAM:1764.4/21") parse_aprs("Lachens>APRS,TCPIP*,qAC,GLIDERN2:/165334h4344.70NI00639.19E&/A=005435 v0.2.1 CPU:0.3 RAM:1764.4/21",
datetime(2015, 4, 10, 16, 54))
if __name__ == '__main__': if __name__ == '__main__':

Wyświetl plik

@ -2,6 +2,7 @@ import unittest
from datetime import datetime from datetime import datetime
from ogn.aprs_utils import dmsToDeg, createTimestamp, create_aprs_login from ogn.aprs_utils import dmsToDeg, createTimestamp, create_aprs_login
from ogn.exceptions import AmbigousTimeError
class TestStringMethods(unittest.TestCase): class TestStringMethods(unittest.TestCase):
@ -18,8 +19,8 @@ class TestStringMethods(unittest.TestCase):
self.assertEqual(timestamp, datetime(2015, 10, 16, 0, 0, 1)) self.assertEqual(timestamp, datetime(2015, 10, 16, 0, 0, 1))
def test_createTimestamp_big_difference(self): def test_createTimestamp_big_difference(self):
with self.assertRaises(Exception): with self.assertRaises(AmbigousTimeError):
createTimestamp('123456', reference=datetime(2015, 10, 15, 23, 59, 59), validate=True) createTimestamp('123456', reference=datetime(2015, 10, 15, 23, 59, 59))
def test_create_aprs_login(self): def test_create_aprs_login(self):
basic_login = create_aprs_login('klaus', -1, 'myApp', '0.1') basic_login = create_aprs_login('klaus', -1, 'myApp', '0.1')

Wyświetl plik

@ -1,17 +1,17 @@
# aprsc 2.0.14-g28c5a6a 10 Apr 2015 18:58:47 GMT GLIDERN1 37.187.40.234:14580 # aprsc 2.0.14-g28c5a6a 10 Apr 2015 18:58:47 GMT GLIDERN1 37.187.40.234:14580
FLRDDA5BA>APRS,qAS,LFMX:/160829h4415.41N/00600.03E'342/049/A=005524 id0ADDA5BA -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5 FLRDDA5BA>APRS,qAS,LFMX:/165829h4415.41N/00600.03E'342/049/A=005524 id0ADDA5BA -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5
ICA4B0E3A>APRS,qAS,Letzi:/072319h4711.75N\00802.59E^327/149/A=006498 id154B0E3A -3959fpm +0.5rot 9.0dB 0e -6.3kHz gps1x3 ICA4B0E3A>APRS,qAS,Letzi:/165319h4711.75N\00802.59E^327/149/A=006498 id154B0E3A -3959fpm +0.5rot 9.0dB 0e -6.3kHz gps1x3
Lachens>APRS,TCPIP*,qAC,GLIDERN2:/165334h4344.70NI00639.19E&/A=005435 v0.2.1 CPU:0.3 RAM:1764.4/2121.4MB NTP:2.8ms/+4.9ppm +47.0C RF:+0.70dB Lachens>APRS,TCPIP*,qAC,GLIDERN2:/165334h4344.70NI00639.19E&/A=005435 v0.2.1 CPU:0.3 RAM:1764.4/2121.4MB NTP:2.8ms/+4.9ppm +47.0C RF:+0.70dB
LFGU>APRS,TCPIP*,qAC,GLIDERN2:/190556h4907.63NI00706.41E&/A=000833 v0.2.0 CPU:0.9 RAM:281.3/458.9MB NTP:0.5ms/-19.1ppm +53.0C RF:+0.70dB LFGU>APRS,TCPIP*,qAC,GLIDERN2:/165556h4907.63NI00706.41E&/A=000833 v0.2.0 CPU:0.9 RAM:281.3/458.9MB NTP:0.5ms/-19.1ppm +53.0C RF:+0.70dB
FLRDDB091>APRS,qAS,Letzi:/195831h4740.04N/00806.01EX152/124/A=004881 id06DD8E80 +198fpm +0.0rot 6.5dB 13e +4.0kHz gps3x4 FLRDDB091>APRS,qAS,Letzi:/165831h4740.04N/00806.01EX152/124/A=004881 id06DD8E80 +198fpm +0.0rot 6.5dB 13e +4.0kHz gps3x4
LSGS>APRS,TCPIP*,qAC,GLIDERN1:/195345h4613.25NI00719.68E&/A=001581 CPU:0.7 RAM:247.9/456.4MB NTP:0.7ms/-11.4ppm +44.4C RF:+53+71.9ppm/+0.4dB LSGS>APRS,TCPIP*,qAC,GLIDERN1:/165345h4613.25NI00719.68E&/A=001581 CPU:0.7 RAM:247.9/456.4MB NTP:0.7ms/-11.4ppm +44.4C RF:+53+71.9ppm/+0.4dB
FLRDDDD33>APRS,qAS,LFNF:/165341h4344.27N/00547.41E'/A=000886 id06DDDD33 +020fpm +0.0rot 20.8dB 0e -14.3kHz gps3x4 FLRDDDD33>APRS,qAS,LFNF:/165341h4344.27N/00547.41E'/A=000886 id06DDDD33 +020fpm +0.0rot 20.8dB 0e -14.3kHz gps3x4
FLRDDE026>APRS,qAS,LFNF:/165341h4358.58N/00553.89E'204/055/A=005048 id06DDE026 +257fpm +0.1rot 7.2dB 0e -0.8kHz gps4x7 FLRDDE026>APRS,qAS,LFNF:/165341h4358.58N/00553.89E'204/055/A=005048 id06DDE026 +257fpm +0.1rot 7.2dB 0e -0.8kHz gps4x7
ICA484A9C>APRS,qAS,LFMX:/165341h4403.50N/00559.67E'/A=001460 id05484A9C +000fpm +0.0rot 18.0dB 0e +3.5kHz gps4x7 ICA484A9C>APRS,qAS,LFMX:/165341h4403.50N/00559.67E'/A=001460 id05484A9C +000fpm +0.0rot 18.0dB 0e +3.5kHz gps4x7
WolvesSW>APRS,TCPIP*,qAC,GLIDERN2:/165343h5232.23NI00210.91W&/A=000377 CPU:1.5 RAM:159.9/458.7MB NTP:6.6ms/-36.7ppm +45.5C RF:+130-0.4ppm/-0.1dB WolvesSW>APRS,TCPIP*,qAC,GLIDERN2:/165343h5232.23NI00210.91W&/A=000377 CPU:1.5 RAM:159.9/458.7MB NTP:6.6ms/-36.7ppm +45.5C RF:+130-0.4ppm/-0.1dB
Oxford>APRS,TCPIP*,qAC,GLIDERN1:/190533h5142.96NI00109.68W&/A=000380 v0.1.3 CPU:0.9 RAM:268.8/458.6MB NTP:0.5ms/-45.9ppm +60.5C RF:+55+2.9ppm/+1.54dB Oxford>APRS,TCPIP*,qAC,GLIDERN1:/165533h5142.96NI00109.68W&/A=000380 v0.1.3 CPU:0.9 RAM:268.8/458.6MB NTP:0.5ms/-45.9ppm +60.5C RF:+55+2.9ppm/+1.54dB
OGNE95A16>APRS,qAS,Sylwek:/203641h5001.94N/01956.91E'270/004/A=000000 id07E95A16 +000fpm +0.1rot 37.8dB 0e -0.4kHz OGNE95A16>APRS,qAS,Sylwek:/165641h5001.94N/01956.91E'270/004/A=000000 id07E95A16 +000fpm +0.1rot 37.8dB 0e -0.4kHz
Salland>APRS,TCPIP*,qAC,GLIDERN2:/201426h5227.93NI00620.03E&/A=000049 v0.2.2 CPU:0.7 RAM:659.3/916.9MB NTP:2.5ms/-75.0ppm RF:+0.41dB Salland>APRS,TCPIP*,qAC,GLIDERN2:/165426h5227.93NI00620.03E&/A=000049 v0.2.2 CPU:0.7 RAM:659.3/916.9MB NTP:2.5ms/-75.0ppm RF:+0.41dB
LSGS>APRS,TCPIP*,qAC,GLIDERN1:/195345h4613.25NI00719.68E&/A=001581 CPU:0.7 RAM:247.9/456.4MB NTP:0.7ms/-11.4ppm +44.4C RF:+53+71.9ppm/+0.4dB LSGS>APRS,TCPIP*,qAC,GLIDERN1:/165345h4613.25NI00719.68E&/A=001581 CPU:0.7 RAM:247.9/456.4MB NTP:0.7ms/-11.4ppm +44.4C RF:+53+71.9ppm/+0.4dB
Drenstein>APRS,TCPIP*,qAC,GLIDERN1:/203011h5147.51NI00744.45E&/A=000213 v0.2.2 CPU:0.8 RAM:695.7/4025.5MB NTP:16000.0ms/+0.0ppm +63.0C Drenstein>APRS,TCPIP*,qAC,GLIDERN1:/165011h5147.51NI00744.45E&/A=000213 v0.2.2 CPU:0.8 RAM:695.7/4025.5MB NTP:16000.0ms/+0.0ppm +63.0C
ZK-GSC>APRS,qAS,Omarama:/210202h4429.25S/16959.33E'/A=001407 id05C821EA +020fpm +0.0rot 16.8dB 0e -3.1kHz gps1x3 hear1084 hearB597 hearB598 ZK-GSC>APRS,qAS,Omarama:/165202h4429.25S/16959.33E'/A=001407 id05C821EA +020fpm +0.0rot 16.8dB 0e -3.1kHz gps1x3 hear1084 hearB597 hearB598