kopia lustrzana https://github.com/glidernet/ogn-python
Merge pull request #24 from kerel-fs/aprs/+AmbigousTimeError
Add user-defined exception AmbigousTimeErrorpull/25/head
commit
eb738d232c
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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__':
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue