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

Wyświetl plik

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

Wyświetl plik

@ -1,20 +1,34 @@
"""
exception definitions
"""
from datetime import datetime
class AprsParseError(Exception):
"""Parse error while parsing an aprs packet."""
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.message = "This is not a valid APRS string: {}".format(aprs_string)
super(AprsParseError, self).__init__(self.message)
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):
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.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.aprs_parser import parse_aprs
from ogn.aprs_utils import create_aprs_login
from ogn.exceptions import AprsParseError, OgnParseError
from ogn.exceptions import AprsParseError, OgnParseError, AmbigousTimeError
class ognGateway:
@ -83,6 +83,9 @@ class ognGateway:
except OgnParseError:
self.logger.error('OgnParseError while parsing line: {}'.format(line), exc_info=True)
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:
self.process_beacon(beacon)

Wyświetl plik

@ -1,4 +1,5 @@
import re
from datetime import datetime
from sqlalchemy import Column, String, Integer, Float, DateTime
from sqlalchemy.ext.declarative import AbstractConcreteBase
@ -29,7 +30,7 @@ class Beacon(AbstractConcreteBase, Base):
altitude = Column(Integer)
comment = None
def parse(self, text):
def parse(self, text, reference_date=datetime.utcnow()):
result = re_pattern_aprs.match(text)
if result is None:
raise AprsParseError(text)
@ -37,7 +38,7 @@ class Beacon(AbstractConcreteBase, Base):
self.name = result.group(1)
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)
if result.group(5) == "S":

Wyświetl plik

@ -1,4 +1,5 @@
import unittest
from datetime import datetime
from ogn.aprs_parser import parse_aprs
from ogn.exceptions import AprsParseError, OgnParseError
@ -8,7 +9,7 @@ class TestStringMethods(unittest.TestCase):
def test_valid_beacons(self):
with open('tests/valid_beacons.txt') as f:
for line in f:
parse_aprs(line)
parse_aprs(line, datetime(2015, 4, 10, 17, 0))
def test_fail_none(self):
with self.assertRaises(TypeError):
@ -24,11 +25,13 @@ class TestStringMethods(unittest.TestCase):
def test_incomplete_device_string(self):
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):
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__':

Wyświetl plik

@ -2,6 +2,7 @@ import unittest
from datetime import datetime
from ogn.aprs_utils import dmsToDeg, createTimestamp, create_aprs_login
from ogn.exceptions import AmbigousTimeError
class TestStringMethods(unittest.TestCase):
@ -18,8 +19,8 @@ class TestStringMethods(unittest.TestCase):
self.assertEqual(timestamp, datetime(2015, 10, 16, 0, 0, 1))
def test_createTimestamp_big_difference(self):
with self.assertRaises(Exception):
createTimestamp('123456', reference=datetime(2015, 10, 15, 23, 59, 59), validate=True)
with self.assertRaises(AmbigousTimeError):
createTimestamp('123456', reference=datetime(2015, 10, 15, 23, 59, 59))
def test_create_aprs_login(self):
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
FLRDDA5BA>APRS,qAS,LFMX:/160829h4415.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
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:/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
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
FLRDDB091>APRS,qAS,Letzi:/195831h4740.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
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:/165831h4740.04N/00806.01EX152/124/A=004881 id06DD8E80 +198fpm +0.0rot 6.5dB 13e +4.0kHz gps3x4
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
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
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
OGNE95A16>APRS,qAS,Sylwek:/203641h5001.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
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
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
ZK-GSC>APRS,qAS,Omarama:/210202h4429.25S/16959.33E'/A=001407 id05C821EA +020fpm +0.0rot 16.8dB 0e -3.1kHz gps1x3 hear1084 hearB597 hearB598
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:/165641h5001.94N/01956.91E'270/004/A=000000 id07E95A16 +000fpm +0.1rot 37.8dB 0e -0.4kHz
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:/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:/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:/165202h4429.25S/16959.33E'/A=001407 id05C821EA +020fpm +0.0rot 16.8dB 0e -3.1kHz gps1x3 hear1084 hearB597 hearB598