コード例 #1
0
def create_country_stats(session, date, logger=None):
    if logger is None:
        logger = app.logger

    (start, end) = date_to_timestamps(date)

    # First kill the stats for the selected date
    deleted_counter = session.query(CountryStats).filter(
        CountryStats.date == date).delete()

    country_stats = (session.query(
        literal(date), Country.gid,
        func.count(AircraftBeacon.timestamp).label("aircraft_beacon_count"),
        func.count(func.distinct(
            AircraftBeacon.receiver_id)).label("device_count")).filter(
                between(AircraftBeacon.timestamp, start, end)).filter(
                    func.st_contains(Country.geom,
                                     AircraftBeacon.location)).group_by(
                                         Country.gid).subquery())

    # And insert them
    ins = insert(CountryStats).from_select([
        CountryStats.date, CountryStats.country_id,
        CountryStats.aircraft_beacon_count, CountryStats.device_count
    ], country_stats)
    res = session.execute(ins)
    insert_counter = res.rowcount
    session.commit()
コード例 #2
0
def update_max_altitudes(session, date, logger=None):
    """Add max altitudes in logbook when flight is complete (takeoff and landing)."""

    if logger is None:
        logger = app.logger

    logger.info("Update logbook max altitude.")

    if session is None:
        session = app.session

    (start, end) = date_to_timestamps(date)

    logbook_entries = (
        session.query(Logbook.id)
        .filter(and_(Logbook.takeoff_timestamp != null(), Logbook.landing_timestamp != null(), Logbook.max_altitude == null()))
        .filter(between(Logbook.reftime, start, end))
        .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).filter(Logbook.id == max_altitudes.c.id).update({Logbook.max_altitude: max_altitudes.c.max_altitude}, synchronize_session="fetch")

    session.commit()

    finish_message = "Logbook (altitude): {} entries updated.".format(update_logbook)
    logger.info(finish_message)
    return finish_message
コード例 #3
0
ファイル: logbook.py プロジェクト: Meisterschueler/ogn-python
def compute_takeoff_landing(start, end):
    """Compute takeoffs and landings."""

    days = get_database_days(start, end)

    pbar = tqdm(days)
    for single_date in pbar:
        pbar.set_description(datetime.strftime(single_date, "%Y-%m-%d"))
        (start, end) = date_to_timestamps(single_date)
        result = update_takeoff_landings(start=start, end=end)
コード例 #4
0
def create_relation_stats(session, date, logger=None):
    """Add/update relation stats."""

    if logger is None:
        logger = app.logger

    (start, end) = date_to_timestamps(date)

    # First kill the stats for the selected date
    deleted_counter = session.query(RelationStats).filter(
        RelationStats.date == date).delete()

    # Calculate stats for selected day
    relation_stats = (session.query(
        literal(date), AircraftBeacon.device_id, AircraftBeacon.receiver_id,
        func.max(AircraftBeacon.quality),
        func.count(AircraftBeacon.timestamp)).filter(
            and_(
                between(AircraftBeacon.timestamp, start, end),
                AircraftBeacon.distance > 1000,
                AircraftBeacon.error_count == 0,
                AircraftBeacon.quality <= MAX_PLAUSIBLE_QUALITY,
                AircraftBeacon.ground_speed > 10,
            )).group_by(literal(date), AircraftBeacon.device_id,
                        AircraftBeacon.receiver_id).subquery())

    # And insert them
    ins = insert(RelationStats).from_select([
        RelationStats.date, RelationStats.device_id, RelationStats.receiver_id,
        RelationStats.quality, RelationStats.beacon_count
    ], relation_stats)
    res = session.execute(ins)
    insert_counter = res.rowcount
    session.commit()
    logger.warn("RelationStats for {}: {} deleted, {} inserted".format(
        date, deleted_counter, insert_counter))

    return "RelationStats for {}: {} deleted, {} inserted".format(
        date, deleted_counter, insert_counter)
コード例 #5
0
ファイル: logbook.py プロジェクト: nferruzzi/ogn-python
def show(airport_name, date=None):
    """Show a logbook for <airport_name>."""
    airport = db.session.query(Airport).filter(
        Airport.name == airport_name).first()

    if airport is None:
        print('Airport "{}" not found.'.format(airport_name))
        return

    or_args = []
    if date is not None:
        date = datetime.strptime(date, "%Y-%m-%d")
        (start, end) = date_to_timestamps(date)
        or_args = [db.between(Logbook.reftime, start, end)]

    # get all logbook entries and add device and airport infos
    logbook_query = (db.session.query(
        func.row_number().over(order_by=Logbook.reftime).label("row_number"),
        Logbook).filter(*or_args).filter(
            db.or_(Logbook.takeoff_airport_id == airport.id,
                   Logbook.landing_airport_id == airport.id)).order_by(
                       Logbook.reftime))

    # ... and finally print out the logbook
    print("--- Logbook ({}) ---".format(airport_name))

    def none_datetime_replacer(datetime_object):
        return "--:--:--" if datetime_object is None else datetime_object.time(
        )

    def none_track_replacer(track_object):
        return "--" if track_object is None else round(track_object / 10.0)

    def none_timedelta_replacer(timedelta_object):
        return "--:--:--" if timedelta_object is None else timedelta_object

    def none_registration_replacer(device_object):
        return "[" + device_object.address + "]" if len(
            device_object.infos) == 0 else device_object.infos[0].registration

    def none_aircraft_replacer(device_object):
        return "(unknown)" if len(
            device_object.infos) == 0 else device_object.infos[0].aircraft

    def airport_marker(logbook_object):
        if logbook_object.takeoff_airport is not None and logbook_object.takeoff_airport.name is not airport.name:
            return "FROM: {}".format(logbook_object.takeoff_airport.name)
        elif logbook_object.landing_airport is not None and logbook_object.landing_airport.name is not airport.name:
            return "TO: {}".format(logbook_object.landing_airport.name)
        else:
            return ""

    def none_altitude_replacer(logbook_object):
        return "?" if logbook_object.max_altitude is None else "{:5d}m ({:+5d}m)".format(
            logbook_object.max_altitude, logbook_object.max_altitude -
            logbook_object.takeoff_airport.altitude)

    for [row_number, logbook] in logbook_query.all():
        print("%3d. %10s   %8s (%2s)   %8s (%2s)   %8s  %15s %8s   %17s %20s" %
              (
                  row_number,
                  logbook.reftime.date(),
                  none_datetime_replacer(logbook.takeoff_timestamp),
                  none_track_replacer(logbook.takeoff_track),
                  none_datetime_replacer(logbook.landing_timestamp),
                  none_track_replacer(logbook.landing_track),
                  none_timedelta_replacer(logbook.duration),
                  none_altitude_replacer(logbook),
                  none_registration_replacer(logbook.device),
                  none_aircraft_replacer(logbook.device),
                  airport_marker(logbook),
              ))
コード例 #6
0
def update_device_stats_jumps(session, date, logger=None):
    """Update device stats jumps."""

    if logger is None:
        logger = app.logger

    (start, end) = date_to_timestamps(date)

    # speed limits in m/s (values above indicates a unplausible position / jump)
    max_horizontal_speed = 1000
    max_vertical_speed = 100
    max_jumps = 10  # threshold for an 'ambiguous' device

    # find consecutive positions for a device
    sq = (session.query(
        AircraftBeacon.device_id,
        AircraftBeacon.timestamp,
        func.lead(AircraftBeacon.timestamp).over(
            partition_by=AircraftBeacon.device_id,
            order_by=AircraftBeacon.timestamp).label("timestamp_next"),
        AircraftBeacon.location_wkt,
        func.lead(AircraftBeacon.location_wkt).over(
            partition_by=AircraftBeacon.device_id,
            order_by=AircraftBeacon.timestamp).label("location_next"),
        AircraftBeacon.altitude,
        func.lead(AircraftBeacon.altitude).over(
            partition_by=AircraftBeacon.device_id,
            order_by=AircraftBeacon.timestamp).label("altitude_next"),
    ).filter(
        and_(between(AircraftBeacon.timestamp, start, end),
             AircraftBeacon.error_count == 0)).subquery())

    # calc vertial and horizontal speed between points
    sq2 = (session.query(
        sq.c.device_id,
        (func.st_distancesphere(sq.c.location_next, sq.c.location) /
         (func.extract("epoch", sq.c.timestamp_next) -
          func.extract("epoch", sq.c.timestamp))).label("horizontal_speed"),
        ((sq.c.altitude_next - sq.c.altitude) /
         (func.extract("epoch", sq.c.timestamp_next) -
          func.extract("epoch", sq.c.timestamp))).label("vertical_speed"),
    ).filter(
        and_(sq.c.timestamp != null(), sq.c.timestamp_next != null(),
             sq.c.timestamp < sq.c.timestamp_next)).subquery())

    # ... and find and count 'jumps'
    sq3 = (session.query(
        sq2.c.device_id,
        func.sum(
            case([(or_(
                func.abs(sq2.c.horizontal_speed) > max_horizontal_speed,
                func.abs(sq2.c.vertical_speed) > max_vertical_speed), 1)],
                 else_=0)).label("jumps")).group_by(
                     sq2.c.device_id).subquery())

    upd = update(DeviceStats).where(
        and_(DeviceStats.date == date,
             DeviceStats.device_id == sq3.c.device_id)).values({
                 "ambiguous":
                 sq3.c.jumps > max_jumps,
                 "jumps":
                 sq3.c.jumps
             })

    result = session.execute(upd)
    update_counter = result.rowcount
    session.commit()
    logger.warn("Updated {} DeviceStats jumps".format(update_counter))

    return "DeviceStats jumps for {}: {} updated".format(date, update_counter)
コード例 #7
0
def create_device_stats(session, date, logger=None):
    """Add/update device stats."""

    if logger is None:
        logger = app.logger

    (start, end) = date_to_timestamps(date)

    # First kill the stats for the selected date
    deleted_counter = session.query(DeviceStats).filter(
        DeviceStats.date == date).delete()

    # Since "distinct count" does not work in window functions we need a work-around for receiver counting
    sq = (session.query(
        AircraftBeacon,
        func.dense_rank().over(
            partition_by=AircraftBeacon.device_id,
            order_by=AircraftBeacon.receiver_id).label("dr")).filter(
                and_(between(AircraftBeacon.timestamp, start, end),
                     AircraftBeacon.device_id != null())).filter(
                         or_(AircraftBeacon.error_count == 0,
                             AircraftBeacon.error_count == null())).subquery())

    # Calculate stats, firstseen, lastseen and last values != NULL
    device_stats = session.query(
        distinct(sq.c.device_id).label("device_id"),
        literal(date).label("date"),
        func.max(
            sq.c.dr).over(partition_by=sq.c.device_id).label("receiver_count"),
        func.max(sq.c.altitude).over(
            partition_by=sq.c.device_id).label("max_altitude"),
        func.count(sq.c.device_id).over(
            partition_by=sq.c.device_id).label("aircraft_beacon_count"),
        func.first_value(sq.c.name).over(
            partition_by=sq.c.device_id,
            order_by=case(
                [(sq.c.name == null(), None)],
                else_=sq.c.timestamp).asc().nullslast()).label("name"),
        func.first_value(sq.c.timestamp).over(
            partition_by=sq.c.device_id,
            order_by=case(
                [(sq.c.timestamp == null(), None)],
                else_=sq.c.timestamp).asc().nullslast()).label("firstseen"),
        func.first_value(sq.c.timestamp).over(
            partition_by=sq.c.device_id,
            order_by=case(
                [(sq.c.timestamp == null(), None)],
                else_=sq.c.timestamp).desc().nullslast()).label("lastseen"),
        func.first_value(sq.c.aircraft_type).over(
            partition_by=sq.c.device_id,
            order_by=case([(sq.c.aircraft_type == null(), None)],
                          else_=sq.c.timestamp).desc().nullslast()).label(
                              "aircraft_type"),
        func.first_value(sq.c.stealth).over(
            partition_by=sq.c.device_id,
            order_by=case(
                [(sq.c.stealth == null(), None)],
                else_=sq.c.timestamp).desc().nullslast()).label("stealth"),
        func.first_value(sq.c.software_version).over(
            partition_by=sq.c.device_id,
            order_by=case([(sq.c.software_version == null(), None)],
                          else_=sq.c.timestamp).desc().nullslast()).label(
                              "software_version"),
        func.first_value(sq.c.hardware_version).over(
            partition_by=sq.c.device_id,
            order_by=case([(sq.c.hardware_version == null(), None)],
                          else_=sq.c.timestamp).desc().nullslast()).label(
                              "hardware_version"),
        func.first_value(sq.c.real_address).over(
            partition_by=sq.c.device_id,
            order_by=case([(sq.c.real_address == null(), None)],
                          else_=sq.c.timestamp).desc().nullslast()).label(
                              "real_address"),
    ).subquery()

    # And insert them
    ins = insert(DeviceStats).from_select(
        [
            DeviceStats.device_id,
            DeviceStats.date,
            DeviceStats.receiver_count,
            DeviceStats.max_altitude,
            DeviceStats.aircraft_beacon_count,
            DeviceStats.name,
            DeviceStats.firstseen,
            DeviceStats.lastseen,
            DeviceStats.aircraft_type,
            DeviceStats.stealth,
            DeviceStats.software_version,
            DeviceStats.hardware_version,
            DeviceStats.real_address,
        ],
        device_stats,
    )
    res = session.execute(ins)
    insert_counter = res.rowcount
    session.commit()
    logger.debug("DeviceStats for {}: {} deleted, {} inserted".format(
        date, deleted_counter, insert_counter))

    return "DeviceStats for {}: {} deleted, {} inserted".format(
        date, deleted_counter, insert_counter)
コード例 #8
0
def create_receiver_stats(session, date, logger=None):
    """Add/update receiver stats."""

    if logger is None:
        logger = app.logger

    (start, end) = date_to_timestamps(date)

    # First kill the stats for the selected date
    deleted_counter = session.query(ReceiverStats).filter(
        ReceiverStats.date == date).delete()

    # Select one day
    sq = session.query(ReceiverBeacon).filter(
        between(ReceiverBeacon.timestamp, start, end)).subquery()

    # Calculate stats, firstseen, lastseen and last values != NULL
    receiver_stats = session.query(
        distinct(sq.c.receiver_id).label("receiver_id"),
        literal(date).label("date"),
        func.first_value(sq.c.timestamp).over(
            partition_by=sq.c.receiver_id,
            order_by=case(
                [(sq.c.timestamp == null(), None)],
                else_=sq.c.timestamp).asc().nullslast()).label("firstseen"),
        func.first_value(sq.c.timestamp).over(
            partition_by=sq.c.receiver_id,
            order_by=case(
                [(sq.c.timestamp == null(), None)],
                else_=sq.c.timestamp).desc().nullslast()).label("lastseen"),
        func.first_value(sq.c.location).over(
            partition_by=sq.c.receiver_id,
            order_by=case([(sq.c.location == null(), None)],
                          else_=sq.c.timestamp).desc().nullslast()).label(
                              "location_wkt"),
        func.first_value(sq.c.altitude).over(
            partition_by=sq.c.receiver_id,
            order_by=case(
                [(sq.c.altitude == null(), None)],
                else_=sq.c.timestamp).desc().nullslast()).label("altitude"),
        func.first_value(sq.c.version).over(
            partition_by=sq.c.receiver_id,
            order_by=case(
                [(sq.c.version == null(), None)],
                else_=sq.c.timestamp).desc().nullslast()).label("version"),
        func.first_value(sq.c.platform).over(
            partition_by=sq.c.receiver_id,
            order_by=case(
                [(sq.c.platform == null(), None)],
                else_=sq.c.timestamp).desc().nullslast()).label("platform"),
    ).subquery()

    # And insert them
    ins = insert(ReceiverStats).from_select(
        [
            ReceiverStats.receiver_id,
            ReceiverStats.date,
            ReceiverStats.firstseen,
            ReceiverStats.lastseen,
            ReceiverStats.location_wkt,
            ReceiverStats.altitude,
            ReceiverStats.version,
            ReceiverStats.platform,
        ],
        receiver_stats,
    )
    res = session.execute(ins)
    insert_counter = res.rowcount
    session.commit()
    logger.warn("ReceiverStats for {}: {} deleted, {} inserted".format(
        date, deleted_counter, insert_counter))

    # Update aircraft_beacon_count, aircraft_count and max_distance
    aircraft_beacon_stats = (session.query(
        AircraftBeacon.receiver_id,
        func.count(AircraftBeacon.timestamp).label("aircraft_beacon_count"),
        func.count(func.distinct(
            AircraftBeacon.device_id)).label("aircraft_count"),
        func.max(AircraftBeacon.distance).label("max_distance"),
    ).filter(
        and_(between(AircraftBeacon.timestamp, start,
                     end), AircraftBeacon.error_count == 0,
             AircraftBeacon.quality <= MAX_PLAUSIBLE_QUALITY,
             AircraftBeacon.relay == null())).group_by(
                 AircraftBeacon.receiver_id).subquery())

    upd = (update(ReceiverStats).where(
        and_(ReceiverStats.date == date, ReceiverStats.receiver_id ==
             aircraft_beacon_stats.c.receiver_id)).values({
                 "aircraft_beacon_count":
                 aircraft_beacon_stats.c.aircraft_beacon_count,
                 "aircraft_count":
                 aircraft_beacon_stats.c.aircraft_count,
                 "max_distance":
                 aircraft_beacon_stats.c.max_distance
             }))

    result = session.execute(upd)
    update_counter = result.rowcount
    session.commit()
    logger.warn("Updated {} ReceiverStats".format(update_counter))

    return "ReceiverStats for {}: {} deleted, {} inserted, {} updated".format(
        date, deleted_counter, insert_counter, update_counter)
コード例 #9
0
ファイル: ognrange.py プロジェクト: nferruzzi/ogn-python
def update_entries(session, date, logger=None):
    """Create receiver coverage stats for Melissas ognrange."""

    if logger is None:
        logger = app.logger

    logger.info("Compute receiver coverages.")

    (start, end) = date_to_timestamps(date)

    # Filter aircraft beacons
    sq = (session.query(
        AircraftBeacon.location_mgrs_short, AircraftBeacon.receiver_id,
        AircraftBeacon.signal_quality, AircraftBeacon.altitude,
        AircraftBeacon.device_id).filter(
            and_(between(AircraftBeacon.timestamp, start,
                         end), AircraftBeacon.location_mgrs_short != null(),
                 AircraftBeacon.receiver_id != null(),
                 AircraftBeacon.device_id != null())).subquery())

    # ... and group them by reduced MGRS, receiver and date
    query = (session.query(
        sq.c.location_mgrs_short,
        sq.c.receiver_id,
        func.cast(date, Date).label("date"),
        func.max(sq.c.signal_quality).label("max_signal_quality"),
        func.min(sq.c.altitude).label("min_altitude"),
        func.max(sq.c.altitude).label("max_altitude"),
        func.count(sq.c.altitude).label("aircraft_beacon_count"),
        func.count(func.distinct(sq.c.device_id)).label("device_count"),
    ).group_by(sq.c.location_mgrs_short, sq.c.receiver_id).subquery())

    # if a receiver coverage entry exist --> update it
    upd = (update(ReceiverCoverage).where(
        and_(
            ReceiverCoverage.location_mgrs_short ==
            query.c.location_mgrs_short,
            ReceiverCoverage.receiver_id == query.c.receiver_id,
            ReceiverCoverage.date == date)).values({
                "max_signal_quality":
                query.c.max_signal_quality,
                "min_altitude":
                query.c.min_altitude,
                "max_altitude":
                query.c.max_altitude,
                "aircraft_beacon_count":
                query.c.aircraft_beacon_count,
                "device_count":
                query.c.device_count,
            }))

    result = session.execute(upd)
    update_counter = result.rowcount
    session.commit()
    logger.debug(
        "Updated receiver coverage entries: {}".format(update_counter))

    # if a receiver coverage entry doesnt exist --> insert it
    new_coverage_entries = session.query(query).filter(~exists().where(
        and_(
            ReceiverCoverage.location_mgrs_short ==
            query.c.location_mgrs_short, ReceiverCoverage.receiver_id ==
            query.c.receiver_id, ReceiverCoverage.date == date)))

    ins = insert(ReceiverCoverage).from_select(
        (
            ReceiverCoverage.location_mgrs_short,
            ReceiverCoverage.receiver_id,
            ReceiverCoverage.date,
            ReceiverCoverage.max_signal_quality,
            ReceiverCoverage.min_altitude,
            ReceiverCoverage.max_altitude,
            ReceiverCoverage.aircraft_beacon_count,
            ReceiverCoverage.device_count,
        ),
        new_coverage_entries,
    )

    result = session.execute(ins)
    insert_counter = result.rowcount
    session.commit()

    finish_message = "ReceiverCoverage: {} inserted, {} updated".format(
        insert_counter, update_counter)
    logger.debug(finish_message)
    return finish_message
コード例 #10
0
def update_logbook(offset_days=None):
    """Add/update logbook entries."""

    current_app.logger.info("Compute logbook.")

    # limit time range to given date and set window partition and window order
    if offset_days:
        (start, end) = date_to_timestamps(datetime.utcnow() -
                                          timedelta(days=offset_days))
    else:
        (start, end) = date_to_timestamps(datetime.utcnow().date())
    pa = TakeoffLanding.sender_id
    wo = db.and_(TakeoffLanding.sender_id, TakeoffLanding.timestamp,
                 TakeoffLanding.airport_id)

    # make a query with previous, current and next "takeoff_landing" event, so we can find complete flights
    sq = (db.session.query(
        TakeoffLanding.sender_id,
        db.func.lag(TakeoffLanding.sender_id).over(
            partition_by=pa, order_by=wo).label("sender_id_prev"),
        db.func.lead(TakeoffLanding.sender_id).over(
            partition_by=pa,
            order_by=wo).label("sender_id_next"), TakeoffLanding.timestamp,
        db.func.lag(TakeoffLanding.timestamp).over(
            partition_by=pa, order_by=wo).label("timestamp_prev"),
        db.func.lead(TakeoffLanding.timestamp).over(
            partition_by=pa,
            order_by=wo).label("timestamp_next"), TakeoffLanding.track,
        db.func.lag(TakeoffLanding.track).over(
            partition_by=pa, order_by=wo).label("track_prev"),
        db.func.lead(TakeoffLanding.track).over(
            partition_by=pa, order_by=wo).label("track_next"),
        TakeoffLanding.is_takeoff,
        db.func.lag(TakeoffLanding.is_takeoff).over(
            partition_by=pa, order_by=wo).label("is_takeoff_prev"),
        db.func.lead(TakeoffLanding.is_takeoff).over(
            partition_by=pa, order_by=wo).label("is_takeoff_next"),
        TakeoffLanding.airport_id,
        db.func.lag(TakeoffLanding.airport_id).over(
            partition_by=pa, order_by=wo).label("airport_id_prev"),
        db.func.lead(TakeoffLanding.airport_id).over(
            partition_by=pa, order_by=wo).label("airport_id_next")).subquery())

    # find (new) starts without landing
    only_starts_query = (db.session.query(
        sq.c.sender_id.label("sender_id"),
        sq.c.timestamp.label("takeoff_timestamp"),
        sq.c.track.label("takeoff_track"),
        sq.c.airport_id.label("takeoff_airport_id")
    ).filter(sq.c.is_takeoff == db.true()).filter(
        db.or_(
            sq.c.is_takeoff_next == db.true(),
            sq.c.is_takeoff_next == db.null())).filter(~Logbook.query.filter(
                db.and_(Logbook.sender_id == sq.c.sender_id,
                        Logbook.takeoff_timestamp == sq.c.timestamp, Logbook.
                        takeoff_airport_id == sq.c.airport_id)).exists()))
    ins = insert(Logbook).from_select(
        (Logbook.sender_id, Logbook.takeoff_timestamp, Logbook.takeoff_track,
         Logbook.takeoff_airport_id),
        only_starts_query,
    )
    result = db.session.execute(ins)
    current_app.logger.debug(f"Added {result.rowcount} starts")
    db.session.commit()

    # find (new) landings without start
    only_landings_query = (db.session.query(
        sq.c.sender_id.label("sender_id"),
        sq.c.timestamp.label("landing_timestamp"),
        sq.c.track.label("landing_track"),
        sq.c.airport_id.label("landing_airport_id"),
    ).filter(
        db.or_(
            sq.c.is_takeoff_prev == db.false(),
            sq.c.is_takeoff_prev == db.null())).filter(
                sq.c.is_takeoff == db.false()).filter(~Logbook.query.filter(
                    db.and_(Logbook.sender_id == sq.c.sender_id, Logbook.
                            landing_timestamp == sq.c.timestamp, Logbook.
                            landing_airport_id == sq.c.airport_id)).exists()))
    ins = insert(Logbook).from_select(
        (Logbook.sender_id, Logbook.landing_timestamp, Logbook.landing_track,
         Logbook.landing_airport_id),
        only_landings_query,
    )
    result = db.session.execute(ins)
    current_app.logger.debug(f"Added {result.rowcount} landings")
    db.session.commit()

    # find complete flights
    complete_flight_query = (db.session.query(
        sq.c.sender_id.label("sender_id"),
        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"),
    ).filter(sq.c.is_takeoff == db.true()).filter(
        sq.c.is_takeoff_next == db.false()).subquery())

    # insert (new) flights
    new_flights_query = (
        db.session.query(complete_flight_query).filter(~Logbook.query.filter(
            db.and_(
                Logbook.sender_id == complete_flight_query.c.sender_id,
                Logbook.landing_timestamp == complete_flight_query.c.
                landing_timestamp, Logbook.landing_airport_id ==
                complete_flight_query.c.landing_airport_id)).exists()).
        filter(~Logbook.query.filter(
            db.and_(
                Logbook.sender_id == complete_flight_query.c.sender_id,
                Logbook.takeoff_timestamp == complete_flight_query.c.
                takeoff_timestamp, Logbook.takeoff_airport_id ==
                complete_flight_query.c.takeoff_airport_id)).exists()))
    ins = insert(Logbook).from_select(
        (Logbook.sender_id, Logbook.takeoff_timestamp, Logbook.takeoff_track,
         Logbook.takeoff_airport_id, Logbook.landing_timestamp,
         Logbook.landing_track, Logbook.landing_airport_id), new_flights_query)
    result = db.session.execute(ins)
    current_app.logger.debug(f"Added {result.rowcount} complete flights")
    db.session.commit()

    # update existing landing with takeoff from complete flight
    upd = db.update(Logbook) \
        .where(db.and_(
            Logbook.sender_id == complete_flight_query.c.sender_id,
            Logbook.takeoff_timestamp == db.null(),
            Logbook.takeoff_airport_id == db.null(),
            Logbook.landing_timestamp != db.null(),
            Logbook.landing_timestamp == complete_flight_query.c.landing_timestamp,
            Logbook.landing_airport_id == complete_flight_query.c.landing_airport_id
        )) \
        .values(takeoff_timestamp=complete_flight_query.c.takeoff_timestamp,
                takeoff_track=complete_flight_query.c.takeoff_track,
                takeoff_airport_id=complete_flight_query.c.takeoff_airport_id)
    result = db.session.execute(upd)
    current_app.logger.debug(
        f"Updated {result.rowcount} takeoffs to complete flights")
    db.session.commit()

    # update existing takeoff with landing from complete flight
    upd = db.update(Logbook) \
        .where(db.and_(
            Logbook.sender_id == complete_flight_query.c.sender_id,
            Logbook.takeoff_timestamp != db.null(),
            Logbook.takeoff_timestamp == complete_flight_query.c.takeoff_timestamp,
            Logbook.takeoff_airport_id == complete_flight_query.c.takeoff_airport_id,
            Logbook.landing_timestamp == db.null(),
            Logbook.landing_airport_id == db.null()
        )) \
        .values(landing_timestamp=complete_flight_query.c.landing_timestamp,
                landing_track=complete_flight_query.c.landing_track,
                landing_airport_id=complete_flight_query.c.landing_airport_id)
    result = db.session.execute(upd)
    current_app.logger.debug(
        f"Updated {result.rowcount} landings to complete flights")
    db.session.commit()

    return
コード例 #11
0
def update_entries(session, date, logger=None):
    """Add/update logbook entries."""

    if logger is None:
        logger = current_app.logger

    logger.info("Compute logbook.")

    # limit time range to given date and set window partition and window order
    (start, end) = date_to_timestamps(date)
    pa = TakeoffLanding.device_id
    wo = and_(TakeoffLanding.device_id, TakeoffLanding.airport_id,
              TakeoffLanding.timestamp)

    # make a query with current, previous and next "takeoff_landing" event, so we can find complete flights
    sq = (session.query(
        TakeoffLanding.device_id,
        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"),
        TakeoffLanding.timestamp,
        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"),
        TakeoffLanding.track,
        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"),
        TakeoffLanding.is_takeoff,
        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"),
        TakeoffLanding.airport_id,
        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"),
    ).filter(between(TakeoffLanding.timestamp, start, end)).subquery())

    # find complete flights
    complete_flight_query = session.query(
        sq.c.timestamp.label("reftime"),
        sq.c.device_id.label("device_id"),
        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"),
    ).filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false()))

    # find landings without start
    only_landings_query = (session.query(
        sq.c.timestamp.label("reftime"),
        sq.c.device_id.label("device_id"),
        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"),
    ).filter(sq.c.is_takeoff == false()).filter(
        or_(sq.c.is_takeoff_prev == false(), sq.c.is_takeoff_prev == null())))

    # find starts without landing
    only_starts_query = (session.query(
        sq.c.timestamp.label("reftime"),
        sq.c.device_id.label("device_id"),
        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"),
    ).filter(sq.c.is_takeoff == true()).filter(
        or_(sq.c.is_takeoff_next == true(), sq.c.is_takeoff_next == null())))

    # unite all computated flights
    union_query = complete_flight_query.union(only_landings_query,
                                              only_starts_query).subquery()

    # if a logbook entry exist --> update it
    upd = (update(Logbook).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,
                    Logbook.landing_airport_id == null()),
                and_(
                    Logbook.takeoff_airport_id == null(),
                    Logbook.landing_airport_id ==
                    union_query.c.landing_airport_id, Logbook.landing_timestamp
                    == union_query.c.landing_timestamp),
            ),
        )).values({
            "reftime": union_query.c.reftime,
            "takeoff_timestamp": union_query.c.takeoff_timestamp,
            "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,
        }))

    result = session.execute(upd)
    update_counter = result.rowcount
    session.commit()
    logger.debug("Updated logbook entries: {}".format(update_counter))

    # if a logbook entry doesnt exist --> insert it
    new_logbook_entries = session.query(union_query).filter(~exists().where(
        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),
                and_(Logbook.takeoff_airport_id == null(),
                     union_query.c.takeoff_airport_id == null()),
            ),
            or_(
                and_(
                    Logbook.landing_airport_id ==
                    union_query.c.landing_airport_id, Logbook.landing_timestamp
                    == union_query.c.landing_timestamp),
                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,
        ),
        new_logbook_entries,
    )

    result = session.execute(ins)
    insert_counter = result.rowcount
    session.commit()

    finish_message = "Logbook: {} inserted, {} updated".format(
        insert_counter, update_counter)
    logger.debug(finish_message)
    return finish_message