ogn-python/ogn_python/collect/logbook.py

173 wiersze
8.4 KiB
Python
Czysty Zwykły widok Historia

2019-01-01 19:13:08 +00:00
from sqlalchemy import and_, or_, insert, update, exists, between
2016-07-02 18:07:22 +00:00
from sqlalchemy.sql import func, null
2016-11-01 07:30:05 +00:00
from sqlalchemy.sql.expression import true, false
2015-11-11 07:04:42 +00:00
from ogn_python.model import TakeoffLanding, Logbook, AircraftBeacon
from ogn_python.utils import date_to_timestamps
2015-11-11 07:04:42 +00:00
2019-03-10 14:58:10 +00:00
from ogn_python import app
2015-11-11 07:04:42 +00:00
2019-03-10 14:58:10 +00:00
def update_entries(session, date, logger=None):
2017-12-16 21:18:04 +00:00
"""Add/update logbook entries."""
2019-03-10 14:58:10 +00:00
if logger is None:
logger = app.logger
2016-06-29 21:26:30 +00:00
2019-03-10 14:58:10 +00:00
logger.info("Compute logbook.")
2016-07-02 18:07:22 +00:00
2019-01-10 21:35:19 +00:00
# limit time range to given date and set window partition and window order
2019-04-14 17:57:40 +00:00
(start, end) = date_to_timestamps(date)
pa = (TakeoffLanding.device_id)
wo = and_(TakeoffLanding.device_id,
TakeoffLanding.airport_id,
TakeoffLanding.timestamp)
2019-01-01 19:13:08 +00:00
2016-06-29 21:26:30 +00:00
# make a query with current, previous and next "takeoff_landing" event, so we can find complete flights
2016-07-02 18:07:22 +00:00
sq = session.query(
2016-07-01 05:19:31 +00:00
TakeoffLanding.device_id,
2019-01-10 21:35:19 +00:00
func.lag(TakeoffLanding.device_id).over(partition_by=pa, order_by=wo).label('device_id_prev'),
func.lead(TakeoffLanding.device_id).over(partition_by=pa, order_by=wo).label('device_id_next'),
2016-07-01 05:19:31 +00:00
TakeoffLanding.timestamp,
2019-01-10 21:35:19 +00:00
func.lag(TakeoffLanding.timestamp).over(partition_by=pa, order_by=wo).label('timestamp_prev'),
func.lead(TakeoffLanding.timestamp).over(partition_by=pa, order_by=wo).label('timestamp_next'),
2016-07-01 05:19:31 +00:00
TakeoffLanding.track,
2019-01-10 21:35:19 +00:00
func.lag(TakeoffLanding.track).over(partition_by=pa, order_by=wo).label('track_prev'),
func.lead(TakeoffLanding.track).over(partition_by=pa, order_by=wo).label('track_next'),
2016-07-01 05:19:31 +00:00
TakeoffLanding.is_takeoff,
2019-01-10 21:35:19 +00:00
func.lag(TakeoffLanding.is_takeoff).over(partition_by=pa, order_by=wo).label('is_takeoff_prev'),
func.lead(TakeoffLanding.is_takeoff).over(partition_by=pa, order_by=wo).label('is_takeoff_next'),
2016-07-01 05:19:31 +00:00
TakeoffLanding.airport_id,
2019-01-10 21:35:19 +00:00
func.lag(TakeoffLanding.airport_id).over(partition_by=pa, order_by=wo).label('airport_id_prev'),
func.lead(TakeoffLanding.airport_id).over(partition_by=pa, order_by=wo).label('airport_id_next')) \
2019-04-14 17:57:40 +00:00
.filter(between(TakeoffLanding.timestamp, start, end)) \
2016-06-29 21:26:30 +00:00
.subquery()
2019-01-10 21:35:19 +00:00
# find complete flights
2016-07-02 18:07:22 +00:00
complete_flight_query = session.query(
2016-06-29 21:26:30 +00:00
sq.c.timestamp.label('reftime'),
sq.c.device_id.label('device_id'),
2016-06-30 20:43:09 +00:00
sq.c.timestamp.label('takeoff_timestamp'), sq.c.track.label('takeoff_track'), sq.c.airport_id.label('takeoff_airport_id'),
sq.c.timestamp_next.label('landing_timestamp'), sq.c.track_next.label('landing_track'), sq.c.airport_id_next.label('landing_airport_id')) \
2019-01-10 21:35:19 +00:00
.filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false()))
2016-06-29 21:26:30 +00:00
# find landings without start
2016-07-02 18:07:22 +00:00
only_landings_query = session.query(
2016-06-29 21:26:30 +00:00
sq.c.timestamp.label('reftime'),
sq.c.device_id.label('device_id'),
2016-06-30 20:43:09 +00:00
null().label('takeoff_timestamp'), null().label('takeoff_track'), null().label('takeoff_airport_id'),
sq.c.timestamp.label('landing_timestamp'), sq.c.track.label('landing_track'), sq.c.airport_id.label('landing_airport_id')) \
2016-06-29 21:26:30 +00:00
.filter(sq.c.is_takeoff == false()) \
2019-01-10 21:35:19 +00:00
.filter(or_(sq.c.is_takeoff_prev == false(),
2016-07-02 14:31:33 +00:00
sq.c.is_takeoff_prev == null()))
2016-06-29 21:26:30 +00:00
# find starts without landing
2016-07-02 18:07:22 +00:00
only_starts_query = session.query(
2016-06-29 21:26:30 +00:00
sq.c.timestamp.label('reftime'),
sq.c.device_id.label('device_id'),
2016-06-30 20:43:09 +00:00
sq.c.timestamp.label('takeoff_timestamp'), sq.c.track.label('takeoff_track'), sq.c.airport_id.label('takeoff_airport_id'),
null().label('landing_timestamp'), null().label('landing_track'), null().label('landing_airport_id')) \
2016-06-29 21:26:30 +00:00
.filter(sq.c.is_takeoff == true()) \
2019-01-10 21:35:19 +00:00
.filter(or_(sq.c.is_takeoff_next == true(),
2016-07-02 14:31:33 +00:00
sq.c.is_takeoff_next == null()))
2016-06-29 21:26:30 +00:00
2016-07-06 17:34:55 +00:00
# unite all computated flights
union_query = complete_flight_query.union(
only_landings_query,
only_starts_query) \
.subquery()
2016-06-30 20:43:09 +00:00
2016-07-06 17:34:55 +00:00
# if a logbook entry exist --> update it
2016-06-30 20:43:09 +00:00
upd = update(Logbook) \
2016-07-06 17:34:55 +00:00
.where(and_(Logbook.device_id == union_query.c.device_id,
union_query.c.takeoff_airport_id != null(),
union_query.c.landing_airport_id != null(),
or_(and_(Logbook.takeoff_airport_id == union_query.c.takeoff_airport_id,
Logbook.takeoff_timestamp == union_query.c.takeoff_timestamp,
2016-07-04 20:54:37 +00:00
Logbook.landing_airport_id == null()),
and_(Logbook.takeoff_airport_id == null(),
2016-07-06 17:34:55 +00:00
Logbook.landing_airport_id == union_query.c.landing_airport_id,
Logbook.landing_timestamp == union_query.c.landing_timestamp)))) \
2017-12-16 14:59:41 +00:00
.values({"reftime": union_query.c.reftime,
"takeoff_timestamp": union_query.c.takeoff_timestamp,
2016-07-06 17:34:55 +00:00
"takeoff_track": union_query.c.takeoff_track,
"takeoff_airport_id": union_query.c.takeoff_airport_id,
"landing_timestamp": union_query.c.landing_timestamp,
"landing_track": union_query.c.landing_track,
"landing_airport_id": union_query.c.landing_airport_id})
2016-06-30 20:43:09 +00:00
2016-07-02 18:07:22 +00:00
result = session.execute(upd)
2016-07-04 20:54:37 +00:00
update_counter = result.rowcount
2016-07-02 18:07:22 +00:00
session.commit()
2016-07-04 20:54:37 +00:00
logger.debug("Updated logbook entries: {}".format(update_counter))
2016-06-30 20:43:09 +00:00
2016-07-06 17:34:55 +00:00
# if a logbook entry doesnt exist --> insert it
2016-07-02 18:07:22 +00:00
new_logbook_entries = session.query(union_query) \
2016-06-29 21:26:30 +00:00
.filter(~exists().where(
2016-07-04 20:54:37 +00:00
and_(Logbook.device_id == union_query.c.device_id,
or_(and_(Logbook.takeoff_airport_id == union_query.c.takeoff_airport_id,
Logbook.takeoff_timestamp == union_query.c.takeoff_timestamp),
2016-06-29 21:26:30 +00:00
and_(Logbook.takeoff_airport_id == null(),
union_query.c.takeoff_airport_id == null())),
2016-07-04 20:54:37 +00:00
or_(and_(Logbook.landing_airport_id == union_query.c.landing_airport_id,
Logbook.landing_timestamp == union_query.c.landing_timestamp),
2016-06-29 21:26:30 +00:00
and_(Logbook.landing_airport_id == null(),
union_query.c.landing_airport_id == null())))))
ins = insert(Logbook).from_select((Logbook.reftime,
Logbook.device_id,
Logbook.takeoff_timestamp,
Logbook.takeoff_track,
Logbook.takeoff_airport_id,
Logbook.landing_timestamp,
Logbook.landing_track,
Logbook.landing_airport_id),
2016-06-29 21:26:30 +00:00
new_logbook_entries)
2016-07-02 18:07:22 +00:00
result = session.execute(ins)
2016-07-04 20:54:37 +00:00
insert_counter = result.rowcount
2016-07-02 18:07:22 +00:00
session.commit()
2016-06-29 21:26:30 +00:00
2019-03-30 16:50:29 +00:00
finish_message = "Logbook: {} inserted, {} updated".format(insert_counter, update_counter)
logger.debug(finish_message)
return finish_message
2017-12-10 19:07:37 +00:00
2019-04-14 17:57:40 +00:00
def update_max_altitudes(session, date, logger=None):
2017-12-16 21:18:04 +00:00
"""Add max altitudes in logbook when flight is complete (takeoff and landing)."""
2019-03-10 14:58:10 +00:00
if logger is None:
logger = app.logger
2017-12-10 19:07:37 +00:00
logger.info("Update logbook max altitude.")
if session is None:
session = app.session
2019-04-14 17:57:40 +00:00
(start, end) = date_to_timestamps(date)
2017-12-10 19:07:37 +00:00
logbook_entries = session.query(Logbook.id) \
.filter(and_(Logbook.takeoff_timestamp != null(), Logbook.landing_timestamp != null(), Logbook.max_altitude == null())) \
2019-04-14 17:57:40 +00:00
.filter(between(Logbook.reftime, start, end)) \
2017-12-10 19:07:37 +00:00
.subquery()
max_altitudes = session.query(Logbook.id, func.max(AircraftBeacon.altitude).label('max_altitude')) \
.filter(Logbook.id == logbook_entries.c.id) \
.filter(and_(AircraftBeacon.device_id == Logbook.device_id,
AircraftBeacon.timestamp >= Logbook.takeoff_timestamp,
AircraftBeacon.timestamp <= Logbook.landing_timestamp)) \
.group_by(Logbook.id) \
.subquery()
update_logbook = session.query(Logbook) \
2017-12-10 19:07:37 +00:00
.filter(Logbook.id == max_altitudes.c.id) \
.update({
Logbook.max_altitude: max_altitudes.c.max_altitude},
synchronize_session='fetch')
session.commit()
2019-03-30 16:50:29 +00:00
finish_message = "Logbook (altitude): {} entries updated.".format(update_logbook)
logger.info(finish_message)
return finish_message