Introduce relations - scheme refactoring

pull/52/head
Konstantin Gründger 2016-05-22 07:23:22 +02:00
rodzic 61f6194d8c
commit 132ae96499
10 zmienionych plików z 281 dodań i 100 usunięć

Wyświetl plik

@ -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'])

Wyświetl plik

@ -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()

Wyświetl plik

@ -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)))

Wyświetl plik

@ -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))

Wyświetl plik

@ -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,

Wyświetl plik

@ -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,

Wyświetl plik

@ -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,

Wyświetl plik

@ -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:

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)