kopia lustrzana https://github.com/glidernet/ogn-python
Introduce relations - scheme refactoring
rodzic
61f6194d8c
commit
132ae96499
|
@ -0,0 +1,83 @@
|
|||
"""Create relations
|
||||
|
||||
Revision ID: 46d818bc09b
|
||||
Revises: 2004ce1566c
|
||||
Create Date: 2016-05-18 21:00:24.832298
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '46d818bc09b'
|
||||
down_revision = '2004ce1566c'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import geoalchemy2 as ga
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('aircraft_beacon', sa.Column('device_id', sa.Integer))
|
||||
op.create_foreign_key("aircraft_beacon_device_id_fkey", "aircraft_beacon", "device", ["device_id"], ["id"], ondelete="SET NULL")
|
||||
op.create_index('ix_aircraft_beacon_device_id', 'aircraft_beacon', ['device_id'])
|
||||
|
||||
op.add_column('aircraft_beacon', sa.Column('receiver_id', sa.Integer))
|
||||
op.create_foreign_key("aircraft_beacon_receiver_id_fkey", "aircraft_beacon", "receiver", ["receiver_id"], ["id"], ondelete="SET NULL")
|
||||
op.create_index('ix_aircraft_beacon_receiver_id', 'aircraft_beacon', ['receiver_id'])
|
||||
|
||||
op.drop_index('ix_aircraft_beacon_address', 'aircraft_beacon')
|
||||
|
||||
op.add_column('receiver_beacon', sa.Column('receiver_id', sa.Integer))
|
||||
op.create_foreign_key("receiver_beacon_receiver_id_fkey", "receiver_beacon", "receiver", ["receiver_id"], ["id"], ondelete="SET NULL")
|
||||
op.create_index('ix_receiver_beacon_receiver_id', 'receiver_beacon', ['receiver_id'])
|
||||
|
||||
|
||||
op.add_column('takeoff_landing', sa.Column('airport_id', sa.Integer))
|
||||
op.create_foreign_key("takeoff_landing_airport_id_fkey", "takeoff_landing", "airport", ["airport_id"], ["id"], ondelete="SET NULL")
|
||||
op.create_index('ix_takeoff_landing_airport_id', 'takeoff_landing', ['airport_id'])
|
||||
|
||||
op.add_column('takeoff_landing', sa.Column('device_id', sa.Integer))
|
||||
op.create_foreign_key('takeoff_landing_device_id_fkey', 'takeoff_landing', 'device', ['device_id'], ['id'], ondelete="SET NULL")
|
||||
op.create_index('ix_takeoff_landing_device_id', 'takeoff_landing', ['device_id'])
|
||||
|
||||
op.drop_index('ix_takeoff_landing_address', 'takeoff_landing')
|
||||
op.drop_index('idx_takeoff_landing_location', 'takeoff_landing')
|
||||
op.drop_column('takeoff_landing', 'address')
|
||||
op.drop_column('takeoff_landing', 'name')
|
||||
op.drop_column('takeoff_landing', 'receiver_name')
|
||||
op.drop_column('takeoff_landing', 'location')
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_index('ix_aircraft_beacon_device_id', 'aircraft_beacon')
|
||||
op.drop_foreign_key("aircraft_beacon_device_id_fkey", "aircraft_beacon")
|
||||
op.drop_column('aircraft_beacon', 'device_id')
|
||||
|
||||
op.drop_index('ix_aircraft_beacon_receiver_id', 'aircraft_beacon')
|
||||
op.drop_foreign_key("aircraft_beacon_receiver_id_fkey", "aircraft_beacon")
|
||||
op.drop_column('aircraft_beacon', 'receiver_id')
|
||||
|
||||
op.create_index('ix_aircraft_beacon_address', sa.Column('address', sa.String))
|
||||
|
||||
|
||||
op.drop_index('ix_receiver_beacon_receiver_id', 'receiver_beacon')
|
||||
op.drop_foreign_key("ix_receiver_beacon_receiver_id", "receiver_beacon")
|
||||
op.drop_column('receiver_beacon', 'receiver_id')
|
||||
|
||||
|
||||
op.drop_index('ix_takeoff_landing_airport_id', 'takeoff_landing')
|
||||
op.drop_foreign_key("takeoff_landing_airport_id_fkey", "takeoff_landing")
|
||||
op.drop_column('takeoff_landing', 'airport_id')
|
||||
|
||||
op.drop_index('ix_takeoff_landing_device_id', 'takeoff_landing')
|
||||
op.drop_foreign_key("takeoff_landing_device_id_fkey", "takeoff_landing")
|
||||
op.drop_column('takeoff_landing', 'device_id')
|
||||
|
||||
op.add_column('takeoff_landing', sa.Column('name', sa.String))
|
||||
op.add_column('takeoff_landing', sa.Column('receiver_name', sa.String(9)))
|
||||
op.add_column('takeoff_landing', sa.Column('address', sa.String(6)))
|
||||
op.add_column('takeoff_landing', sa.Column('location', ga.Geometry('POINT', srid=4326)))
|
||||
op.create_index('ix_takeoff_landing_address', 'takeoff_landing', ['address'])
|
||||
op.create_index('idx_takeoff_landing_location', 'takeoff_landing', ['location'])
|
||||
|
|
@ -4,10 +4,10 @@ from celery.utils.log import get_task_logger
|
|||
from ogn.collect.celery import app
|
||||
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy import and_, or_, insert
|
||||
from sqlalchemy import and_, or_, insert, between
|
||||
from sqlalchemy.sql.expression import case
|
||||
|
||||
from ogn.model import AircraftBeacon, TakeoffLanding
|
||||
from ogn.model import AircraftBeacon, TakeoffLanding, Airport
|
||||
|
||||
logger = get_task_logger(__name__)
|
||||
|
||||
|
@ -22,7 +22,11 @@ def compute_takeoff_and_landing():
|
|||
duration = 100 # the points must not exceed this duration
|
||||
radius = 0.05 # the points must not exceed this radius (degree!) around the 2nd point
|
||||
|
||||
# calculate the time where the computation starts
|
||||
# takeoff / landing has to be near an airport
|
||||
airport_radius = 0.05 # takeoff / landing must not exceed this radius (degree!) around the airport
|
||||
airport_delta = 200 # takeoff / landing must not exceed this altitude offset above/below the airport
|
||||
|
||||
# calculate the start (and stop) timestamp for the computatio
|
||||
last_takeoff_landing_query = app.session.query(func.max(TakeoffLanding.timestamp))
|
||||
begin_computation = last_takeoff_landing_query.one()[0]
|
||||
if begin_computation is None:
|
||||
|
@ -37,55 +41,47 @@ def compute_takeoff_and_landing():
|
|||
app.session.query(TakeoffLanding) \
|
||||
.filter(TakeoffLanding.timestamp >= begin_computation) \
|
||||
.delete()
|
||||
end_computation = begin_computation + timedelta(days=30)
|
||||
end_computation = begin_computation + timedelta(days=5)
|
||||
|
||||
logger.debug("Calculate takeoffs and landings between {} and {}"
|
||||
.format(begin_computation, end_computation))
|
||||
|
||||
# make a query with current, previous and next position
|
||||
sq = app.session.query(
|
||||
AircraftBeacon.address,
|
||||
func.lag(AircraftBeacon.address).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('address_prev'),
|
||||
func.lead(AircraftBeacon.address).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('address_next'),
|
||||
AircraftBeacon.timestamp,
|
||||
func.lag(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_prev'),
|
||||
func.lead(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_next'),
|
||||
AircraftBeacon.name,
|
||||
func.lag(AircraftBeacon.name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('name_prev'),
|
||||
func.lead(AircraftBeacon.name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('name_next'),
|
||||
AircraftBeacon.receiver_name,
|
||||
func.lag(AircraftBeacon.receiver_name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('receiver_name_prev'),
|
||||
func.lead(AircraftBeacon.receiver_name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('receiver_name_next'),
|
||||
func.lag(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('timestamp_prev'),
|
||||
func.lead(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('timestamp_next'),
|
||||
AircraftBeacon.location_wkt,
|
||||
func.lag(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_prev'),
|
||||
func.lead(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_next'),
|
||||
func.lag(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('location_wkt_prev'),
|
||||
func.lead(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('location_wkt_next'),
|
||||
AircraftBeacon.track,
|
||||
func.lag(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('track_prev'),
|
||||
func.lead(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('track_next'),
|
||||
func.lag(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('track_prev'),
|
||||
func.lead(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('track_next'),
|
||||
AircraftBeacon.ground_speed,
|
||||
func.lag(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('ground_speed_prev'),
|
||||
func.lead(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('ground_speed_next'),
|
||||
func.lag(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('ground_speed_prev'),
|
||||
func.lead(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('ground_speed_next'),
|
||||
AircraftBeacon.altitude,
|
||||
func.lag(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('altitude_prev'),
|
||||
func.lead(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('altitude_next')) \
|
||||
func.lag(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('altitude_prev'),
|
||||
func.lead(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('altitude_next'),
|
||||
AircraftBeacon.device_id,
|
||||
func.lag(AircraftBeacon.device_id).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('device_id_prev'),
|
||||
func.lead(AircraftBeacon.device_id).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('device_id_next')) \
|
||||
.filter(AircraftBeacon.timestamp >= begin_computation) \
|
||||
.filter(AircraftBeacon.timestamp <= end_computation) \
|
||||
.order_by(func.date(AircraftBeacon.timestamp), AircraftBeacon.address, AircraftBeacon.timestamp) \
|
||||
.subquery()
|
||||
|
||||
# find takeoffs and landings
|
||||
takeoff_landing_query = app.session.query(
|
||||
sq.c.address,
|
||||
sq.c.name,
|
||||
sq.c.receiver_name,
|
||||
# find possible takeoffs and landings
|
||||
sq2 = app.session.query(
|
||||
sq.c.timestamp,
|
||||
sq.c.location,
|
||||
sq.c.track,
|
||||
case([(sq.c.ground_speed > takeoff_speed, sq.c.track),
|
||||
(sq.c.ground_speed < landing_speed, sq.c.track_prev)]).label('track'), # on landing we take the track from the previous fix because gliders tend to leave the runway quickly
|
||||
sq.c.ground_speed,
|
||||
sq.c.altitude,
|
||||
case([(sq.c.ground_speed > takeoff_speed, True),
|
||||
(sq.c.ground_speed < landing_speed, False)]).label('is_takeoff')) \
|
||||
.filter(sq.c.address_prev == sq.c.address == sq.c.address_next) \
|
||||
(sq.c.ground_speed < landing_speed, False)]).label('is_takeoff'),
|
||||
sq.c.device_id) \
|
||||
.filter(sq.c.device_id_prev == sq.c.device_id == sq.c.device_id_next) \
|
||||
.filter(or_(and_(sq.c.ground_speed_prev < takeoff_speed, # takeoff
|
||||
sq.c.ground_speed > takeoff_speed,
|
||||
sq.c.ground_speed_next > takeoff_speed),
|
||||
|
@ -95,10 +91,29 @@ def compute_takeoff_and_landing():
|
|||
.filter(sq.c.timestamp_next - sq.c.timestamp_prev < timedelta(seconds=duration)) \
|
||||
.filter(and_(func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_prev, radius),
|
||||
func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_next, radius))) \
|
||||
.order_by(func.date(sq.c.timestamp), sq.c.timestamp)
|
||||
.subquery()
|
||||
|
||||
# consider them if they are near a airport
|
||||
takeoff_landing_query = app.session.query(
|
||||
sq2.c.timestamp,
|
||||
sq2.c.track,
|
||||
sq2.c.ground_speed,
|
||||
sq2.c.altitude,
|
||||
sq2.c.is_takeoff,
|
||||
sq2.c.device_id,
|
||||
Airport.id) \
|
||||
.filter(and_(func.ST_DFullyWithin(sq2.c.location, Airport.location_wkt, airport_radius),
|
||||
between(sq2.c.altitude, Airport.altitude-airport_delta, Airport.altitude+airport_delta)))
|
||||
|
||||
# ... and save them
|
||||
ins = insert(TakeoffLanding).from_select((TakeoffLanding.address, TakeoffLanding.name, TakeoffLanding.receiver_name, TakeoffLanding.timestamp, TakeoffLanding.location_wkt, TakeoffLanding.track, TakeoffLanding.ground_speed, TakeoffLanding.altitude, TakeoffLanding.is_takeoff), takeoff_landing_query)
|
||||
ins = insert(TakeoffLanding).from_select((TakeoffLanding.timestamp,
|
||||
TakeoffLanding.track,
|
||||
TakeoffLanding.ground_speed,
|
||||
TakeoffLanding.altitude,
|
||||
TakeoffLanding.is_takeoff,
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.airport_id),
|
||||
takeoff_landing_query)
|
||||
result = app.session.execute(ins)
|
||||
counter = result.rowcount
|
||||
app.session.commit()
|
||||
|
|
|
@ -24,8 +24,9 @@ def compute():
|
|||
print("New/recalculated takeoffs/landings: {}".format(counter))
|
||||
|
||||
|
||||
@manager.arg('utc_delta_hours', help='delta hours to utc (for local time logs)')
|
||||
@manager.command
|
||||
def show(airport_name):
|
||||
def show(airport_name, utc_delta_hours=0):
|
||||
"""Show a logbook for <airport_name>."""
|
||||
airport = session.query(Airport) \
|
||||
.filter(Airport.name == airport_name) \
|
||||
|
@ -35,88 +36,85 @@ def show(airport_name):
|
|||
print('Airport "{}" not found.'.format(airport_name))
|
||||
return
|
||||
|
||||
delta_altitude = 200
|
||||
delta_radius = 0.01 # degree!
|
||||
utc_timedelta = timedelta(hours=utc_delta_hours)
|
||||
|
||||
# make a query with current, previous and next "takeoff_landing" event, so we can find complete flights
|
||||
sq = session.query(
|
||||
TakeoffLanding.address,
|
||||
func.lag(TakeoffLanding.address)
|
||||
TakeoffLanding.device_id,
|
||||
func.lag(TakeoffLanding.device_id)
|
||||
.over(
|
||||
order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
.label('address_prev'),
|
||||
func.lead(TakeoffLanding.address)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
.label('address_next'),
|
||||
TakeoffLanding.timestamp,
|
||||
order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('device_id_prev'),
|
||||
func.lead(TakeoffLanding.device_id)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('device_id_next'),
|
||||
(TakeoffLanding.timestamp+utc_timedelta).label('timestamp'),
|
||||
func.lag(TakeoffLanding.timestamp)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('timestamp_prev'),
|
||||
func.lead(TakeoffLanding.timestamp)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
func.lead(TakeoffLanding.timestamp+utc_timedelta)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('timestamp_next'),
|
||||
TakeoffLanding.track,
|
||||
func.lag(TakeoffLanding.track)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('track_prev'),
|
||||
func.lead(TakeoffLanding.track)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('track_next'),
|
||||
TakeoffLanding.is_takeoff,
|
||||
func.lag(TakeoffLanding.is_takeoff)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('is_takeoff_prev'),
|
||||
func.lead(TakeoffLanding.is_takeoff)
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp),
|
||||
TakeoffLanding.address,
|
||||
TakeoffLanding.timestamp))
|
||||
.over(order_by=and_(func.date(TakeoffLanding.timestamp+utc_timedelta),
|
||||
TakeoffLanding.device_id,
|
||||
TakeoffLanding.timestamp+utc_timedelta))
|
||||
.label('is_takeoff_next')) \
|
||||
.filter(func.ST_DFullyWithin(TakeoffLanding.location_wkt, Airport.location_wkt, delta_radius)) \
|
||||
.filter(TakeoffLanding.altitude < Airport.altitude + delta_altitude) \
|
||||
.filter(Airport.name == airport.name) \
|
||||
.filter(TakeoffLanding.airport_id == airport.id) \
|
||||
.subquery()
|
||||
|
||||
# find complete flights (with takeoff and landing) with duration < 1 day
|
||||
complete_flight_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), label('duration', sq.c.timestamp_next - sq.c.timestamp)) \
|
||||
complete_flight_query = session.query(sq.c.timestamp.label('reftime'), sq.c.device_id.label('device_id'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), label('duration', sq.c.timestamp_next - sq.c.timestamp)) \
|
||||
.filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \
|
||||
.filter(sq.c.address == sq.c.address_next) \
|
||||
.filter(sq.c.device_id == sq.c.device_id_next) \
|
||||
.filter(sq.c.timestamp_next - sq.c.timestamp < timedelta(days=1))
|
||||
|
||||
# split complete flights (with takeoff and landing) with duration > 1 day into one takeoff and one landing
|
||||
split_start_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), null().label('landing'), null().label('landing_track'), null().label('duration')) \
|
||||
split_start_query = session.query(sq.c.timestamp.label('reftime'), sq.c.device_id.label('device_id'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), null().label('landing'), null().label('landing_track'), null().label('duration')) \
|
||||
.filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \
|
||||
.filter(sq.c.address == sq.c.address_next) \
|
||||
.filter(sq.c.device_id == sq.c.device_id_next) \
|
||||
.filter(sq.c.timestamp_next - sq.c.timestamp >= timedelta(days=1))
|
||||
|
||||
split_landing_query = session.query(sq.c.timestamp_next.label('reftime'), sq.c.address.label('address'), null().label('takeoff'), null().label('takeoff_track'), sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), null().label('duration')) \
|
||||
split_landing_query = session.query(sq.c.timestamp_next.label('reftime'), sq.c.device_id.label('device_id'), null().label('takeoff'), null().label('takeoff_track'), sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), null().label('duration')) \
|
||||
.filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \
|
||||
.filter(sq.c.address == sq.c.address_next) \
|
||||
.filter(sq.c.device_id == sq.c.device_id_next) \
|
||||
.filter(sq.c.timestamp_next - sq.c.timestamp >= timedelta(days=1))
|
||||
|
||||
# find landings without start
|
||||
only_landings_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), null().label('takeoff'), null().label('takeoff_track'), sq.c.timestamp.label('landing'), sq.c.track_next.label('landing_track'), null().label('duration')) \
|
||||
only_landings_query = session.query(sq.c.timestamp.label('reftime'), sq.c.device_id.label('device_id'), null().label('takeoff'), null().label('takeoff_track'), sq.c.timestamp.label('landing'), sq.c.track_next.label('landing_track'), null().label('duration')) \
|
||||
.filter(sq.c.is_takeoff == false()) \
|
||||
.filter(or_(sq.c.address != sq.c.address_prev,
|
||||
.filter(or_(sq.c.device_id != sq.c.device_id_prev,
|
||||
sq.c.is_takeoff_prev == false()))
|
||||
|
||||
# find starts without landing
|
||||
only_starts_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), null().label('landing'), null().label('landing_track'), null().label('duration')) \
|
||||
only_starts_query = session.query(sq.c.timestamp.label('reftime'), sq.c.device_id.label('device_id'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), null().label('landing'), null().label('landing_track'), null().label('duration')) \
|
||||
.filter(sq.c.is_takeoff == true()) \
|
||||
.filter(or_(sq.c.address != sq.c.address_next,
|
||||
.filter(or_(sq.c.device_id != sq.c.device_id_next,
|
||||
sq.c.is_takeoff_next == true()))
|
||||
|
||||
# unite all
|
||||
|
@ -130,15 +128,13 @@ def show(airport_name):
|
|||
# get aircraft informations and sort all entries by the reference time
|
||||
logbook_query = session.query(
|
||||
union_query.c.reftime,
|
||||
union_query.c.address,
|
||||
union_query.c.takeoff,
|
||||
union_query.c.takeoff_track,
|
||||
union_query.c.landing,
|
||||
union_query.c.landing_track,
|
||||
union_query.c.duration,
|
||||
Device.registration,
|
||||
Device.aircraft) \
|
||||
.outerjoin(Device, union_query.c.address == Device.address) \
|
||||
Device) \
|
||||
.outerjoin(Device, union_query.c.device_id == Device.id) \
|
||||
.order_by(union_query.c.reftime)
|
||||
|
||||
print('--- Logbook ({}) ---'.format(airport_name))
|
||||
|
@ -152,13 +148,13 @@ def show(airport_name):
|
|||
def none_timedelta_replacer(timedelta_object):
|
||||
return '--:--:--' if timedelta_object is None else timedelta_object
|
||||
|
||||
def none_registration_replacer(registration_object, address):
|
||||
return '[' + address + ']' if registration_object is None else registration_object
|
||||
def none_registration_replacer(device_object):
|
||||
return '[' + device_object.address + ']' if device_object.registration is None else device_object.registration
|
||||
|
||||
def none_aircraft_replacer(aircraft_object):
|
||||
return '(unknown)' if aircraft_object is None else aircraft_object
|
||||
def none_aircraft_replacer(device_object):
|
||||
return '(unknown)' if device_object.aircraft is None else device_object.aircraft
|
||||
|
||||
for [reftime, address, takeoff, takeoff_track, landing, landing_track, duration, registration, aircraft] in logbook_query.all():
|
||||
for [reftime, takeoff, takeoff_track, landing, landing_track, duration, device] in logbook_query.all():
|
||||
print('%10s %8s (%2s) %8s (%2s) %8s %8s %s' % (
|
||||
reftime.date(),
|
||||
none_datetime_replacer(takeoff),
|
||||
|
@ -166,5 +162,5 @@ def show(airport_name):
|
|||
none_datetime_replacer(landing),
|
||||
none_track_replacer(landing_track),
|
||||
none_timedelta_replacer(duration),
|
||||
none_registration_replacer(registration, address),
|
||||
none_aircraft_replacer(aircraft)))
|
||||
none_registration_replacer(device),
|
||||
none_aircraft_replacer(device)))
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import logging
|
||||
from ogn.commands.dbutils import session
|
||||
from ogn.model import AircraftBeacon, ReceiverBeacon, Location
|
||||
from ogn.model import AircraftBeacon, ReceiverBeacon, Device, Receiver, Location
|
||||
from ogn.parser import parse_aprs, parse_ogn_receiver_beacon, parse_ogn_aircraft_beacon, ParseError
|
||||
from ogn.model.address_origin import AddressOrigin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -32,13 +33,48 @@ def process_beacon(raw_message):
|
|||
# /z: ?
|
||||
# /o: ?
|
||||
if message['symboltable'] == "I" and message['symbolcode'] == '&':
|
||||
# ... we have a receiver_beacon
|
||||
message.update(parse_ogn_receiver_beacon(message['comment']))
|
||||
message = replace_lonlat_with_wkt(message)
|
||||
beacon = ReceiverBeacon(**message)
|
||||
|
||||
# connect beacon with receiver
|
||||
receiver = session.query(Receiver.id) \
|
||||
.filter(Receiver.name == beacon.name) \
|
||||
.first()
|
||||
if receiver is None:
|
||||
receiver = Receiver()
|
||||
receiver.name = beacon.name
|
||||
session.add(receiver)
|
||||
beacon.receiver_id = receiver.id
|
||||
else:
|
||||
# ... we have a aircraft_beacon
|
||||
message.update(parse_ogn_aircraft_beacon(message['comment']))
|
||||
message = replace_lonlat_with_wkt(message)
|
||||
beacon = AircraftBeacon(**message)
|
||||
|
||||
# connect beacon with device
|
||||
device = session.query(Device.id) \
|
||||
.filter(Device.address == beacon.address) \
|
||||
.order_by(Device.address_origin) \
|
||||
.first()
|
||||
if device is None:
|
||||
device = Device()
|
||||
device.address = beacon.address
|
||||
device.address_origin = AddressOrigin.seen
|
||||
session.add(device)
|
||||
beacon.device_id = device.id
|
||||
|
||||
# connect beacon with receiver
|
||||
receiver = session.query(Receiver.id) \
|
||||
.filter(Receiver.name == beacon.receiver_name) \
|
||||
.first()
|
||||
if receiver is None:
|
||||
receiver = Receiver()
|
||||
receiver.name = beacon.receiver_name
|
||||
session.add(receiver)
|
||||
beacon.receiver_id = receiver.id
|
||||
|
||||
session.add(beacon)
|
||||
session.commit()
|
||||
logger.debug('Received message: {}'.format(raw_message))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from sqlalchemy import Column, String, Integer, Float, Boolean, SmallInteger
|
||||
from sqlalchemy import Column, String, Integer, Float, Boolean, SmallInteger, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .beacon import Beacon
|
||||
|
||||
|
@ -10,7 +11,7 @@ class AircraftBeacon(Beacon):
|
|||
address_type = Column(SmallInteger)
|
||||
aircraft_type = Column(SmallInteger)
|
||||
stealth = Column(Boolean)
|
||||
address = Column(String(6), index=True)
|
||||
address = Column(String(6))
|
||||
climb_rate = Column(Float)
|
||||
turn_rate = Column(Float)
|
||||
signal_strength = Column(Float)
|
||||
|
@ -24,6 +25,13 @@ class AircraftBeacon(Beacon):
|
|||
|
||||
flightlevel = Column(Float)
|
||||
|
||||
# Relations
|
||||
receiver_id = Column(Integer, ForeignKey('receiver.id', ondelete='SET NULL'), index=True)
|
||||
receiver = relationship('Receiver', foreign_keys=[receiver_id])
|
||||
|
||||
device_id = Column(Integer, ForeignKey('device.id', ondelete='SET NULL'), index=True)
|
||||
device = relationship('Device', foreign_keys=[device_id])
|
||||
|
||||
def __repr__(self):
|
||||
return "<AircraftBeacon %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % (
|
||||
self.name,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from sqlalchemy import Column, String, Integer, Float, SmallInteger
|
||||
from sqlalchemy.orm import relationship
|
||||
from geoalchemy2.types import Geometry
|
||||
|
||||
from .base import Base
|
||||
|
@ -21,6 +22,9 @@ class Airport(Base):
|
|||
runway_length = Column(Integer)
|
||||
frequency = Column(Float)
|
||||
|
||||
# Relations
|
||||
takeoff_landings = relationship('TakeoffLanding')
|
||||
|
||||
def __repr__(self):
|
||||
return "<Airport %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,% s>" % (
|
||||
self.name,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from sqlalchemy import Column, Integer, String, Unicode, Boolean, SmallInteger
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .base import Base
|
||||
|
||||
|
@ -20,6 +21,9 @@ class Device(Base):
|
|||
|
||||
address_origin = Column(SmallInteger)
|
||||
|
||||
# Relations
|
||||
aircraft_beacons = relationship('AircraftBeacon')
|
||||
|
||||
def __repr__(self):
|
||||
return "<Device: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % (
|
||||
self.address_type,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from sqlalchemy import Column, String, Integer, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from geoalchemy2.types import Geometry
|
||||
from geoalchemy2.shape import to_shape
|
||||
|
||||
|
@ -21,6 +22,10 @@ class Receiver(Base):
|
|||
version = Column(String)
|
||||
platform = Column(String)
|
||||
|
||||
# Relations
|
||||
aircraft_beacons = relationship('AircraftBeacon')
|
||||
receiver_beacons = relationship('ReceiverBeacon')
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
if self.location_wkt is None:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from sqlalchemy import Column, Float, String
|
||||
from sqlalchemy import Column, Float, String, Integer, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .beacon import Beacon
|
||||
|
||||
|
@ -20,5 +21,9 @@ class ReceiverBeacon(Beacon):
|
|||
rec_crystal_correction_fine = 0 # obsolete since 0.2.0
|
||||
rec_input_noise = Column(Float)
|
||||
|
||||
# Relations
|
||||
receiver_id = Column(Integer, ForeignKey('receiver.id', ondelete='SET NULL'), index=True)
|
||||
receiver = relationship('Receiver', foreign_keys=[receiver_id])
|
||||
|
||||
def __repr__(self):
|
||||
return "<ReceiverBeacon %s: %s>" % (self.name, self.version)
|
||||
|
|
|
@ -1,10 +1,35 @@
|
|||
from sqlalchemy import Column, String, Boolean
|
||||
from sqlalchemy import Boolean, Column, Float, Integer, DateTime, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from geoalchemy2.types import Geometry
|
||||
from geoalchemy2.shape import to_shape
|
||||
|
||||
from .beacon import Beacon
|
||||
from .base import Base
|
||||
from .geo import Location
|
||||
|
||||
|
||||
class TakeoffLanding(Beacon):
|
||||
class TakeoffLanding(Base):
|
||||
__tablename__ = 'takeoff_landing'
|
||||
|
||||
address = Column(String(6), index=True)
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
altitude = Column(Integer)
|
||||
timestamp = Column(DateTime, index=True)
|
||||
track = Column(Integer)
|
||||
ground_speed = Column(Float)
|
||||
|
||||
is_takeoff = Column(Boolean)
|
||||
|
||||
# Relations
|
||||
airport_id = Column(Integer, ForeignKey('airport.id', ondelete='SET NULL'), index=True)
|
||||
airport = relationship('Airport', foreign_keys=[airport_id])
|
||||
|
||||
device_id = Column(Integer, ForeignKey('device.id', ondelete='SET NULL'), index=True)
|
||||
device = relationship('Device', foreign_keys=[device_id])
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
if self.location_wkt is None:
|
||||
return None
|
||||
|
||||
coords = to_shape(self.location_wkt)
|
||||
return Location(lat=coords.y, lon=coords.x)
|
Ładowanie…
Reference in New Issue