kopia lustrzana https://github.com/glidernet/ogn-python
Refactoring
rodzic
966b7d9c73
commit
28a25048f6
|
@ -131,8 +131,8 @@ def update_devices():
|
|||
synchronize_session='fetch')
|
||||
|
||||
app.session.commit()
|
||||
print("Devices: {} inserted, {} updated".format(insert_count, update_receivers))
|
||||
print("Updated {} AircraftBeacons".format(upd))
|
||||
logger.info("Devices: {} inserted, {} updated".format(insert_count, update_receivers))
|
||||
logger.info("Updated {} AircraftBeacons".format(upd))
|
||||
|
||||
|
||||
@app.task
|
||||
|
@ -220,13 +220,13 @@ def update_receivers():
|
|||
|
||||
app.session.commit()
|
||||
|
||||
print("Receivers: {} inserted, {} updated.".format(insert_count, update_receivers))
|
||||
print("Updated relations: {} aircraft beacons, {} receiver beacons".format(update_aircraft_beacons, update_receiver_beacons))
|
||||
logger.info("Receivers: {} inserted, {} updated.".format(insert_count, update_receivers))
|
||||
logger.info("Updated relations: {} aircraft beacons, {} receiver beacons".format(update_aircraft_beacons, update_receiver_beacons))
|
||||
|
||||
|
||||
@app.task
|
||||
def update_country_code():
|
||||
# update country code if None
|
||||
# update country code in receivers table if None
|
||||
unknown_country_query = app.session.query(Receiver) \
|
||||
.filter(Receiver.country_code == null()) \
|
||||
.filter(Receiver.location_wkt != null()) \
|
||||
|
|
|
@ -11,7 +11,7 @@ logger = get_task_logger(__name__)
|
|||
|
||||
|
||||
@app.task
|
||||
def compute_logbook_entries(session=None):
|
||||
def update_logbook(session=None):
|
||||
logger.info("Compute logbook.")
|
||||
|
||||
if session is None:
|
||||
|
|
|
@ -5,6 +5,7 @@ from celery.utils.log import get_task_logger
|
|||
from sqlalchemy import and_, or_, insert, between, exists
|
||||
from sqlalchemy.sql import func, null
|
||||
from sqlalchemy.sql.expression import case
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from ogn.collect.celery import app
|
||||
from ogn.model import AircraftBeacon, TakeoffLanding, Airport
|
||||
|
@ -13,7 +14,7 @@ logger = get_task_logger(__name__)
|
|||
|
||||
|
||||
@app.task
|
||||
def compute_takeoff_and_landing(session=None):
|
||||
def update_takeoff_landing(session=None):
|
||||
logger.info("Compute takeoffs and landings.")
|
||||
|
||||
if session is None:
|
||||
|
@ -43,73 +44,94 @@ def compute_takeoff_and_landing(session=None):
|
|||
# make a query with current, previous and next position
|
||||
sq = session.query(
|
||||
AircraftBeacon.id,
|
||||
AircraftBeacon.timestamp,
|
||||
func.lag(AircraftBeacon.timestamp).over(order_by=wo).label('timestamp_prev'),
|
||||
func.lead(AircraftBeacon.timestamp).over(order_by=wo).label('timestamp_next'),
|
||||
AircraftBeacon.location_wkt,
|
||||
func.lag(AircraftBeacon.location_wkt).over(order_by=wo).label('location_wkt_prev'),
|
||||
func.lead(AircraftBeacon.location_wkt).over(order_by=wo).label('location_wkt_next'),
|
||||
AircraftBeacon.track,
|
||||
func.lag(AircraftBeacon.track).over(order_by=wo).label('track_prev'),
|
||||
func.lead(AircraftBeacon.track).over(order_by=wo).label('track_next'),
|
||||
AircraftBeacon.ground_speed,
|
||||
func.lag(AircraftBeacon.ground_speed).over(order_by=wo).label('ground_speed_prev'),
|
||||
func.lead(AircraftBeacon.ground_speed).over(order_by=wo).label('ground_speed_next'),
|
||||
AircraftBeacon.altitude,
|
||||
func.lag(AircraftBeacon.altitude).over(order_by=wo).label('altitude_prev'),
|
||||
func.lead(AircraftBeacon.altitude).over(order_by=wo).label('altitude_next'),
|
||||
func.lag(AircraftBeacon.id).over(order_by=wo).label('id_prev'),
|
||||
func.lead(AircraftBeacon.id).over(order_by=wo).label('id_next'),
|
||||
AircraftBeacon.device_id,
|
||||
func.lag(AircraftBeacon.device_id).over(order_by=wo).label('device_id_prev'),
|
||||
func.lead(AircraftBeacon.device_id).over(order_by=wo).label('device_id_next')) \
|
||||
.filter(AircraftBeacon.status == null()) \
|
||||
.filter(and_(AircraftBeacon.timestamp >= '2017-12-09 11:00:00', AircraftBeacon.timestamp <= '2017-12-09 18:00:00')) \
|
||||
.subquery()
|
||||
|
||||
# consider only positions with the same device id
|
||||
sq2 = session.query(sq) \
|
||||
.filter(sq.c.device_id_prev == sq.c.device_id == sq.c.device_id_next) \
|
||||
.filter(sq.c.device_id_prev == sq.c.device_id == sq.c.device_id_next) \
|
||||
.subquery()
|
||||
|
||||
print(sq2)
|
||||
return
|
||||
|
||||
# Get timestamps, locations, tracks, ground_speeds and altitudes
|
||||
prev_ab = aliased(AircraftBeacon, name="prev_ab")
|
||||
lead_ab = aliased(AircraftBeacon, name="lead_ab")
|
||||
|
||||
sq3 = session.query(
|
||||
sq2.c.id,
|
||||
sq2.c.id_prev,
|
||||
sq2.c.id_next,
|
||||
sq2.c.device_id,
|
||||
sq2.c.device_id_prev,
|
||||
sq2.c.device_id_next,
|
||||
AircraftBeacon.timestamp,
|
||||
prev_ab.timestamp.label('timestamp_prev'),
|
||||
lead_ab.timestamp.label('timestamp_next'),
|
||||
AircraftBeacon.location_wkt,
|
||||
prev_ab.location_wkt.label('location_wkt_prev'),
|
||||
lead_ab.location_wkt.label('location_wkt_next'),
|
||||
AircraftBeacon.track,
|
||||
prev_ab.track.label('track_prev'),
|
||||
lead_ab.track.label('track_next'),
|
||||
AircraftBeacon.ground_speed,
|
||||
prev_ab.ground_speed.label('ground_speed_prev'),
|
||||
lead_ab.ground_speed.label('ground_speed_next'),
|
||||
AircraftBeacon.altitude,
|
||||
prev_ab.altitude.label('altitude_prev'),
|
||||
lead_ab.altitude.label('altitude_next')) \
|
||||
.filter(and_(sq2.c.id == AircraftBeacon.id, sq2.c.id_prev == prev_ab.id, sq2.c.id_next == lead_ab.id)) \
|
||||
.subquery()
|
||||
|
||||
# find possible takeoffs and landings
|
||||
sq3 = session.query(
|
||||
sq2.c.id,
|
||||
sq2.c.timestamp,
|
||||
case([(sq2.c.ground_speed > takeoff_speed, sq2.c.location_wkt_prev), # on takeoff we take the location from the previous fix because it is nearer to the airport
|
||||
(sq2.c.ground_speed < landing_speed, sq2.c.location)]).label('location'),
|
||||
case([(sq2.c.ground_speed > takeoff_speed, sq2.c.track),
|
||||
(sq2.c.ground_speed < landing_speed, sq2.c.track_prev)]).label('track'), # on landing we take the track from the previous fix because gliders tend to leave the runway quickly
|
||||
sq2.c.ground_speed,
|
||||
sq2.c.altitude,
|
||||
case([(sq2.c.ground_speed > takeoff_speed, True),
|
||||
(sq2.c.ground_speed < landing_speed, False)]).label('is_takeoff'),
|
||||
sq2.c.device_id) \
|
||||
.filter(sq2.c.timestamp_next - sq2.c.timestamp_prev < timedelta(seconds=duration)) \
|
||||
.filter(and_(func.ST_DFullyWithin(sq2.c.location, sq2.c.location_wkt_prev, radius),
|
||||
func.ST_DFullyWithin(sq2.c.location, sq2.c.location_wkt_next, radius))) \
|
||||
.filter(or_(and_(sq2.c.ground_speed_prev < takeoff_speed, # takeoff
|
||||
sq2.c.ground_speed > takeoff_speed,
|
||||
sq2.c.ground_speed_next > takeoff_speed),
|
||||
and_(sq2.c.ground_speed_prev > landing_speed, # landing
|
||||
sq2.c.ground_speed < landing_speed,
|
||||
sq2.c.ground_speed_next < landing_speed))) \
|
||||
sq4 = session.query(
|
||||
sq3.c.id,
|
||||
sq3.c.timestamp,
|
||||
case([(sq3.c.ground_speed > takeoff_speed, sq3.c.location_wkt_prev), # on takeoff we take the location from the previous fix because it is nearer to the airport
|
||||
(sq3.c.ground_speed < landing_speed, sq3.c.location)]).label('location'),
|
||||
case([(sq3.c.ground_speed > takeoff_speed, sq3.c.track),
|
||||
(sq3.c.ground_speed < landing_speed, sq3.c.track_prev)]).label('track'), # on landing we take the track from the previous fix because gliders tend to leave the runway quickly
|
||||
sq3.c.ground_speed,
|
||||
sq3.c.altitude,
|
||||
case([(sq3.c.ground_speed > takeoff_speed, True),
|
||||
(sq3.c.ground_speed < landing_speed, False)]).label('is_takeoff'),
|
||||
sq3.c.device_id) \
|
||||
.filter(sq3.c.timestamp_next - sq3.c.timestamp_prev < timedelta(seconds=duration)) \
|
||||
.filter(and_(func.ST_DFullyWithin(sq3.c.location, sq3.c.location_wkt_prev, radius),
|
||||
func.ST_DFullyWithin(sq3.c.location, sq3.c.location_wkt_next, radius))) \
|
||||
.filter(or_(and_(sq3.c.ground_speed_prev < takeoff_speed, # takeoff
|
||||
sq3.c.ground_speed > takeoff_speed,
|
||||
sq3.c.ground_speed_next > takeoff_speed),
|
||||
and_(sq3.c.ground_speed_prev > landing_speed, # landing
|
||||
sq3.c.ground_speed < landing_speed,
|
||||
sq3.c.ground_speed_next < landing_speed))) \
|
||||
.subquery()
|
||||
|
||||
# consider them if they are near a airport
|
||||
sq4 = session.query(
|
||||
sq3.c.timestamp,
|
||||
sq3.c.track,
|
||||
sq3.c.is_takeoff,
|
||||
sq3.c.device_id,
|
||||
sq5 = session.query(
|
||||
sq4.c.timestamp,
|
||||
sq4.c.track,
|
||||
sq4.c.is_takeoff,
|
||||
sq4.c.device_id,
|
||||
Airport.id.label('airport_id')) \
|
||||
.filter(and_(func.ST_DFullyWithin(sq3.c.location, Airport.location_wkt, airport_radius),
|
||||
between(sq3.c.altitude, Airport.altitude - airport_delta, Airport.altitude + airport_delta))) \
|
||||
.filter(and_(func.ST_DFullyWithin(sq4.c.location, Airport.location_wkt, airport_radius),
|
||||
between(sq4.c.altitude, Airport.altitude - airport_delta, Airport.altitude + airport_delta))) \
|
||||
.filter(between(Airport.style, 2, 5)) \
|
||||
.subquery()
|
||||
|
||||
# consider them only if they are not already existing in db
|
||||
takeoff_landing_query = session.query(sq4) \
|
||||
takeoff_landing_query = session.query(sq5) \
|
||||
.filter(~exists().where(
|
||||
and_(TakeoffLanding.timestamp == sq4.c.timestamp,
|
||||
TakeoffLanding.device_id == sq4.c.device_id,
|
||||
TakeoffLanding.airport_id == sq4.c.airport_id)))
|
||||
and_(TakeoffLanding.timestamp == sq5.c.timestamp,
|
||||
TakeoffLanding.device_id == sq5.c.device_id,
|
||||
TakeoffLanding.airport_id == sq5.c.airport_id)))
|
||||
|
||||
# ... and save them
|
||||
ins = insert(TakeoffLanding).from_select((TakeoffLanding.timestamp,
|
||||
|
@ -120,7 +142,14 @@ def compute_takeoff_and_landing(session=None):
|
|||
takeoff_landing_query)
|
||||
result = session.execute(ins)
|
||||
counter = result.rowcount
|
||||
|
||||
# mark the computated AircraftBeacons as 'used'
|
||||
update_aircraft_beacons = session.query(AircraftBeacon) \
|
||||
.filter(AircraftBeacon.id == sq2.c.id) \
|
||||
.update({AircraftBeacon.status: 0},
|
||||
synchronize_session='fetch')
|
||||
|
||||
session.commit()
|
||||
logger.debug("New takeoffs and landings: {}".format(counter))
|
||||
logger.debug("Inserted {} TakeoffLandings, updated {} AircraftBeacons".format(counter, update_aircraft_beacons))
|
||||
|
||||
return counter
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
from datetime import timedelta, datetime
|
||||
|
||||
from manager import Manager
|
||||
from ogn.collect.logbook import compute_logbook_entries
|
||||
from ogn.collect.takeoff_landing import compute_takeoff_and_landing
|
||||
from ogn.collect.logbook import update_logbook
|
||||
from ogn.collect.takeoff_landing import update_takeoff_landing
|
||||
from ogn.commands.dbutils import session
|
||||
from ogn.model import Device, DeviceInfo, TakeoffLanding, Airport, Logbook
|
||||
from sqlalchemy import and_, or_
|
||||
|
@ -19,7 +19,7 @@ manager = Manager()
|
|||
def compute_takeoff_landing():
|
||||
"""Compute takeoffs and landings."""
|
||||
print("Compute takeoffs and landings...")
|
||||
result = compute_takeoff_and_landing.delay()
|
||||
result = update_takeoff_landing.delay()
|
||||
counter = result.get()
|
||||
print("New takeoffs/landings: {}".format(counter))
|
||||
|
||||
|
@ -28,7 +28,7 @@ def compute_takeoff_landing():
|
|||
def compute_logbook():
|
||||
"""Compute logbook."""
|
||||
print("Compute logbook...")
|
||||
result = compute_logbook_entries.delay()
|
||||
result = update_logbook.delay()
|
||||
counter = result.get()
|
||||
print("New logbook entries: {}".format(counter))
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import unittest
|
||||
import os
|
||||
|
||||
from ogn.collect.logbook import compute_logbook_entries
|
||||
from ogn.collect.logbook import update_logbook
|
||||
|
||||
|
||||
class TestDB(unittest.TestCase):
|
||||
|
@ -41,10 +41,10 @@ class TestDB(unittest.TestCase):
|
|||
session.execute(self.TAKEOFF_KOENIGSDF_DD0815)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/1')
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/0')
|
||||
|
||||
def test_single_landing(self):
|
||||
|
@ -53,10 +53,10 @@ class TestDB(unittest.TestCase):
|
|||
session.execute(self.LANDING_KOENIGSDF_DD0815)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/1')
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/0')
|
||||
|
||||
def test_different_takeoffs(self):
|
||||
|
@ -66,10 +66,10 @@ class TestDB(unittest.TestCase):
|
|||
session.execute(self.TAKEOFF_OHLSTADT_DD4711)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/2')
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/0')
|
||||
|
||||
def test_takeoff_and_landing(self):
|
||||
|
@ -79,10 +79,10 @@ class TestDB(unittest.TestCase):
|
|||
session.execute(self.LANDING_KOENIGSDF_DD0815)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/1')
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/0')
|
||||
|
||||
def test_takeoff_and_landing_on_different_days(self):
|
||||
|
@ -92,10 +92,10 @@ class TestDB(unittest.TestCase):
|
|||
session.execute(self.LANDING_KOENIGSDF_DD0815_LATER)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/2')
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/0')
|
||||
|
||||
def test_update(self):
|
||||
|
@ -104,22 +104,22 @@ class TestDB(unittest.TestCase):
|
|||
session.execute(self.TAKEOFF_KOENIGSDF_DD0815)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/1')
|
||||
|
||||
session.execute(self.LANDING_KOENIGSDF_DD0815)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '1/0')
|
||||
|
||||
session.execute(self.TAKEOFF_OHLSTADT_DD4711)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/1')
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/0')
|
||||
|
||||
def test_update_wrong_order(self):
|
||||
|
@ -128,13 +128,13 @@ class TestDB(unittest.TestCase):
|
|||
session.execute(self.LANDING_KOENIGSDF_DD0815)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '0/1')
|
||||
|
||||
session.execute(self.TAKEOFF_KOENIGSDF_DD0815)
|
||||
session.commit()
|
||||
|
||||
entries_changed = compute_logbook_entries(session)
|
||||
entries_changed = update_logbook(session)
|
||||
self.assertEqual(entries_changed, '1/0')
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import os
|
|||
|
||||
from ogn.model import TakeoffLanding
|
||||
|
||||
from ogn.collect.takeoff_landing import compute_takeoff_and_landing
|
||||
from ogn.collect.takeoff_landing import update_takeoff_landing
|
||||
|
||||
|
||||
class TestDB(unittest.TestCase):
|
||||
|
@ -30,6 +30,7 @@ class TestDB(unittest.TestCase):
|
|||
session = self.session
|
||||
session.execute("DELETE FROM takeoff_landing")
|
||||
session.execute("DELETE FROM aircraft_beacon")
|
||||
session.execute("DELETE FROM airport")
|
||||
session.commit()
|
||||
pass
|
||||
|
||||
|
@ -44,6 +45,7 @@ class TestDB(unittest.TestCase):
|
|||
return i
|
||||
|
||||
def test_broken_rope(self):
|
||||
"""Fill the db with a winch launch where the rope breaks. The algorithm should detect one takeoff and one landing."""
|
||||
session = self.session
|
||||
|
||||
session.execute("INSERT INTO aircraft_beacon(address, location, altitude, timestamp, track, ground_speed, climb_rate, turn_rate) VALUES('DDEFF7','0101000020E61000009668B61829F12640330E0887F1E94740',604,'2016-07-02 10:47:12',0,0,0,0)")
|
||||
|
@ -95,7 +97,12 @@ class TestDB(unittest.TestCase):
|
|||
session.execute("UPDATE aircraft_beacon SET device_id = d.id FROM device d WHERE d.address='DDEFF7'")
|
||||
session.commit()
|
||||
|
||||
compute_takeoff_and_landing(session)
|
||||
# find the takeoff and the landing
|
||||
update_takeoff_landing(session)
|
||||
self.assertEqual(self.count_takeoff_and_landings(), 2)
|
||||
|
||||
# we should not find the takeoff and the landing again
|
||||
update_takeoff_landing(session)
|
||||
self.assertEqual(self.count_takeoff_and_landings(), 2)
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue