pull/68/head
Konstantin Gründger 2017-12-29 16:30:50 +01:00
rodzic 7729dca315
commit 3b78f0b97d
6 zmienionych plików z 71 dodań i 40 usunięć

Wyświetl plik

@ -1,9 +1,20 @@
from datetime import datetime, timedelta, date from datetime import datetime, timedelta, timezone, date
import os
from sqlalchemy import func, and_, between, case, null from sqlalchemy import func, and_, between, case
from ogn.model import AircraftBeacon, DeviceInfo, Device, Receiver from ogn.model import AircraftBeacon, Device, Receiver
def utc_to_local(utc_dt):
return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None)
def encode(address):
return 'xx' + address
def decode(code):
return code[2:9]
def rec(session): def rec(session):
@ -34,28 +45,25 @@ def lxml(session, show_offline=False, lat_max=90, lat_min=-90, lon_max=180, lon_
else: else:
observation_start = datetime.utcnow() - timedelta(minutes=5) observation_start = datetime.utcnow() - timedelta(minutes=5)
position_query = session.query(Device, AircraftBeacon, DeviceInfo) \ position_query = session.query(AircraftBeacon, Device) \
.filter(and_(between(func.ST_Y(AircraftBeacon.location_wkt), lat_min, lat_max), .filter(and_(between(func.ST_Y(AircraftBeacon.location_wkt), lat_min, lat_max),
between(func.ST_X(AircraftBeacon.location_wkt), lon_min, lon_max))) \ between(func.ST_X(AircraftBeacon.location_wkt), lon_min, lon_max))) \
.filter(Device.lastseen > observation_start) \ .filter(Device.lastseen > observation_start) \
.filter(Device.last_position_beacon_id == AircraftBeacon.id) \ .filter(Device.lastseen == AircraftBeacon.timestamp) \
.outerjoin(DeviceInfo, DeviceInfo.device_id == Device.id) .filter(Device.id == AircraftBeacon.device_id)
lines = list() lines = list()
lines.append('<?xml version="1.0" encoding="UTF-8"?>') lines.append('<?xml version="1.0" encoding="UTF-8"?>')
lines.append('<markers>') lines.append('<markers>')
for [aircraft_beacon, device_info] in position_query.all(): for [aircraft_beacon, device] in position_query.all():
if device_info and (not device_info.tracked or not device_info.identified): code = encode(device.address)
continue
code = encode(aircraft_beacon.address) if len(device.informations) > 0:
device_info = device.informations[0]
if device_info and (not device_info.tracked or not device_info.identified):
continue
if device_info is None:
competition = ('_' + code[-2:]).lower()
registration = code
address = 0
else:
if not device_info.competition: if not device_info.competition:
competition = device_info.registration[-2:] competition = device_info.registration[-2:]
else: else:
@ -66,12 +74,18 @@ def lxml(session, show_offline=False, lat_max=90, lat_min=-90, lon_max=180, lon_
else: else:
registration = device_info.registration registration = device_info.registration
address = device_info.address address = device.address
else:
device_info = None
competition = ('_' + code[-2:]).lower()
registration = code
address = 0
elapsed_time = datetime.utcnow() - aircraft_beacon.timestamp elapsed_time = datetime.utcnow() - aircraft_beacon.timestamp
elapsed_seconds = int(elapsed_time.total_seconds()) elapsed_seconds = int(elapsed_time.total_seconds())
lines.append('<m a="{0:.7f},{1:.7f},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13}"/>' lines.append(' <m a="{0:.7f},{1:.7f},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13}"/>'
.format(aircraft_beacon.location.latitude, .format(aircraft_beacon.location.latitude,
aircraft_beacon.location.longitude, aircraft_beacon.location.longitude,
competition, competition,
@ -81,7 +95,7 @@ def lxml(session, show_offline=False, lat_max=90, lat_min=-90, lon_max=180, lon_
elapsed_seconds, elapsed_seconds,
int(aircraft_beacon.track), int(aircraft_beacon.track),
int(aircraft_beacon.ground_speed), int(aircraft_beacon.ground_speed),
int(aircraft_beacon.climb_rate*10)/10, int(aircraft_beacon.climb_rate * 10) / 10,
aircraft_beacon.aircraft_type, aircraft_beacon.aircraft_type,
aircraft_beacon.receiver_name, aircraft_beacon.receiver_name,
address, address,

Wyświetl plik

@ -21,8 +21,8 @@ def stations2_filtered_pl(session):
query = session.query( query = session.query(
Receiver.name.label('s'), Receiver.name.label('s'),
label('lt', func.round(func.ST_Y(Receiver.location_wkt)*10000)/10000), label('lt', func.round(func.ST_Y(Receiver.location_wkt) * 10000) / 10000),
label('lg', func.round(func.ST_X(Receiver.location_wkt)*10000)/10000), label('lg', func.round(func.ST_X(Receiver.location_wkt) * 10000) / 10000),
case([(Receiver.lastseen > last_10_minutes, "U")], case([(Receiver.lastseen > last_10_minutes, "U")],
else_="D").label('u'), else_="D").label('u'),
Receiver.lastseen.label('ut'), Receiver.lastseen.label('ut'),
@ -30,6 +30,6 @@ def stations2_filtered_pl(session):
.order_by(Receiver.lastseen) .order_by(Receiver.lastseen)
res = session.execute(query) res = session.execute(query)
stations = json.dumps({"stations": [dict(r) for r in res]}, default=alchemyencoder) stations = json.dumps({'stations': [dict(r) for r in res]}, default=alchemyencoder)
return stations return stations

Wyświetl plik

@ -19,6 +19,7 @@ class Device(Base):
# Relations # Relations
aircraft_beacons = relationship('AircraftBeacon') aircraft_beacons = relationship('AircraftBeacon')
informations = relationship('DeviceInfo', backref="device")
def __repr__(self): def __repr__(self):
return "<Device: %s,%s,%s,%s,%s,%s>" % ( return "<Device: %s,%s,%s,%s,%s,%s>" % (

Wyświetl plik

@ -21,7 +21,6 @@ class DeviceInfo(Base):
# Relations # Relations
device_id = Column(Integer, ForeignKey('device.id', ondelete='SET NULL'), index=True) device_id = Column(Integer, ForeignKey('device.id', ondelete='SET NULL'), index=True)
device = relationship('Device', foreign_keys=[device_id])
def __repr__(self): def __repr__(self):
return "<DeviceInfo: %s,%s,%s,%s,%s,%s,%s,%s,%s>" % ( return "<DeviceInfo: %s,%s,%s,%s,%s,%s,%s,%s,%s>" % (

Wyświetl plik

Wyświetl plik

@ -5,10 +5,11 @@ from datetime import datetime
from xmlunittest import XmlTestMixin from xmlunittest import XmlTestMixin
from ogn.model import Receiver, Device from ogn.model import AircraftBeacon, Receiver, Device, DeviceInfo
from ogn.backend.liveglidernet import rec, lxml from ogn.backend.liveglidernet import rec, lxml
from ogn.backend.ognrange import stations2_filtered_pl from ogn.backend.ognrange import stations2_filtered_pl
from ogn.model.aircraft_type import AircraftType
class TestDB(unittest.TestCase, XmlTestMixin): class TestDB(unittest.TestCase, XmlTestMixin):
@ -29,21 +30,37 @@ class TestDB(unittest.TestCase, XmlTestMixin):
self.r01 = Receiver(name='Koenigsdf', location_wkt='0101000020E610000061E8FED7A6EE26407F20661C10EA4740', lastseen='2017-12-20 10:00:00', altitude=601, version='0.2.5', platform='ARM') self.r01 = Receiver(name='Koenigsdf', location_wkt='0101000020E610000061E8FED7A6EE26407F20661C10EA4740', lastseen='2017-12-20 10:00:00', altitude=601, version='0.2.5', platform='ARM')
self.r02 = Receiver(name='Bene', location_wkt='0101000020E6100000D5E76A2BF6C72640D4063A6DA0DB4740', lastseen='2017-12-20 09:45:00', altitude=609, version='0.2.7', platform='x64') self.r02 = Receiver(name='Bene', location_wkt='0101000020E6100000D5E76A2BF6C72640D4063A6DA0DB4740', lastseen='2017-12-20 09:45:00', altitude=609, version='0.2.7', platform='x64')
self.r03 = Receiver(name='Ohlstadt', location_wkt='0101000020E6100000057E678EBF772640A142883E32D44740', lastseen='2017-12-20 10:05:00', altitude=655, version='0.2.6', platform='ARM') self.r03 = Receiver(name='Ohlstadt', location_wkt='0101000020E6100000057E678EBF772640A142883E32D44740', lastseen='2017-12-20 10:05:00', altitude=655, version='0.2.6', platform='ARM')
self.d01 = Device(address='DD4711')
self.d02 = Device(address='DD0815')
session.add(self.r01) session.add(self.r01)
session.add(self.r02) session.add(self.r02)
session.add(self.r03) session.add(self.r03)
session.commit()
self.d01 = Device(address='DD4711', lastseen='2017-12-20 10:00:02')
self.d02 = Device(address='DD0815', lastseen='2017-12-20 09:56:00')
session.add(self.d01) session.add(self.d01)
session.add(self.d02) session.add(self.d02)
session.commit() session.commit()
self.di01 = DeviceInfo(registration='D-4711', competition='Hi', tracked=True, identified=True, device_id=self.d01.id)
session.add(self.di01)
session.commit()
self.ab11 = AircraftBeacon(location_wkt='0101000020E6100000211FF46C56ED26402650D7EDC6E94740', aircraft_type=AircraftType.glider_or_motor_glider, receiver_name='Koenigsdf', timestamp='2017-12-20 10:00:01', track=105, ground_speed=57, climb_rate=-0.5, device_id=self.d01.id)
self.ab12 = AircraftBeacon(location_wkt='0101000020E6100000806DEA295FED2640347D898BB6E94740', aircraft_type=AircraftType.glider_or_motor_glider, receiver_name='Koenigsdf', timestamp='2017-12-20 10:00:02', track=123, ground_speed=55, climb_rate=-0.4, altitude=209, device_id=self.d01.id)
self.ab21 = AircraftBeacon(location_wkt='0101000020E6100000F38B25BF58F22640448B6CE7FBE94740', aircraft_type=AircraftType.powered_aircraft, receiver_name='Koenigsdf', timestamp='2017-12-20 09:54:30', track=280, ground_speed=80, climb_rate=-2.9, device_id=self.d02.id)
self.ab22 = AircraftBeacon(location_wkt='0101000020E6100000A5E8482EFFF12640DC1EAA16FEE94740', aircraft_type=AircraftType.powered_aircraft, receiver_name='Bene', timestamp='2017-12-20 09:56:00', track=270, ground_speed=77, climb_rate=-1.5, altitude=543, device_id=self.d02.id)
session.add(self.ab11)
session.add(self.ab12)
session.add(self.ab21)
session.add(self.ab22)
session.commit()
def tearDown(self): def tearDown(self):
session = self.session session = self.session
session.execute("DELETE FROM device_info")
session.execute("DELETE FROM receiver") session.execute("DELETE FROM receiver")
session.execute("DELETE FROM device")
session.execute("DELETE FROM aircraft_beacon")
session.commit() session.commit()
@mock.patch('ogn.backend.liveglidernet.datetime') @mock.patch('ogn.backend.liveglidernet.datetime')
@ -59,6 +76,7 @@ class TestDB(unittest.TestCase, XmlTestMixin):
self.assertXmlNode(root, tag='markers') self.assertXmlNode(root, tag='markers')
self.assertXpathsOnlyOne(root, ('./m[@a="Koenigsdf"]', './m[@a="Bene"]', './m[@a="Ohlstadt"]')) self.assertXpathsOnlyOne(root, ('./m[@a="Koenigsdf"]', './m[@a="Bene"]', './m[@a="Ohlstadt"]'))
# Check the complete document
expected = """<?xml version="1.0" encoding="UTF-8"?> expected = """<?xml version="1.0" encoding="UTF-8"?>
<markers> <markers>
<m e="0"/> <m e="0"/>
@ -68,26 +86,26 @@ class TestDB(unittest.TestCase, XmlTestMixin):
</markers> </markers>
""".encode(encoding='utf-8') """.encode(encoding='utf-8')
# Check the complete document
self.assertXmlEquivalentOutputs(data, expected) self.assertXmlEquivalentOutputs(data, expected)
print(data) @mock.patch('ogn.backend.liveglidernet.utc_to_local', side_effect=lambda x: x)
@unittest.skip("not finished yet")
@mock.patch('ogn.backend.liveglidernet.datetime') @mock.patch('ogn.backend.liveglidernet.datetime')
def test_lxml(self, datetime_mock): def test_lxml(self, datetime_mock, utc_to_local_mock):
session = self.session session = self.session
datetime_mock.utcnow.return_value = datetime(2017, 12, 20, 10, 0) datetime_mock.utcnow.return_value = datetime(2017, 12, 20, 10, 0, 5)
data = lxml(session).encode(encoding='utf-8') data = lxml(session).encode(encoding='utf-8')
# Check the document # Check the complete document
root = self.assertXmlDocument(data) expected = """<?xml version="1.0" encoding="UTF-8"?>
self.assertXmlNode(root, tag='markers') <markers>
self.assertXpathsOnlyOne(root, ('./m[@a="Koenigsdf"]', './m[@a="Bene"]', './m[@a="Ohlstadt"]')) <m a="47.8258833,11.4636167,Hi,D-4711,209,10:00:02,3,123,55,-0.4,1,Koenigsdf,DD4711,xxDD4711"/>
<m a="47.8280667,11.4726500,_15,xxDD0815,543,09:56:00,245,270,77,-1.5,8,Bene,0,xxDD0815"/>
</markers>
""".encode(encoding='utf-8')
print(data) self.assertXmlEquivalentOutputs(data, expected)
@mock.patch('ogn.backend.ognrange.datetime') @mock.patch('ogn.backend.ognrange.datetime')
def test_stations2_filtered_pl(self, datetime_mock): def test_stations2_filtered_pl(self, datetime_mock):
@ -98,7 +116,6 @@ class TestDB(unittest.TestCase, XmlTestMixin):
import json import json
result = stations2_filtered_pl(session) result = stations2_filtered_pl(session)
print(result)
data = json.loads(result) data = json.loads(result)