From 95fc3b6e6597842492b267304acb62124e53662e Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 10 Aug 2022 20:26:02 +0000 Subject: [PATCH 1/6] Add Functions and Table Structure to Allow Ground Positions Initial commit for enabling ground positions. Adds columns to positions table and ground_position message handler in db-updater, and then add ground_positions endpoint on fids_backend and also attempt to add ground position path to maps endpoint. BCK_6624 --- db-updater/main.py | 12 +++++++++++- fids/app.py | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/db-updater/main.py b/db-updater/main.py index 30c9e8f..63bb99b 100644 --- a/db-updater/main.py +++ b/db-updater/main.py @@ -144,8 +144,11 @@ sa.Column("wind_direction", sa.Integer, key="wind_dir"), sa.Column("wind_quality", sa.Integer), sa.Column("wind_speed", sa.Integer), + # New columns from ground_positions + sa.Column("air_ground", sa.String), + sa.Column("airport", sa.String), ) - VALID_EVENTS = {"position"} + VALID_EVENTS = {"position", "ground_position"} engine_args: dict = {} db_url: str = os.environ["DB_URL"] @@ -480,6 +483,11 @@ def process_keepalive_message(data: dict) -> None: print(f'Based on keepalive["pitr"], we are {behind} behind realtime') +def process_ground_position_message(data: dict) -> None: + """Groundposition message type""" + return add_to_cache(data) + + def disambiguate_altitude(data: dict): """Replaces the alt field in the passed dict with an unambiguous field name""" @@ -534,6 +542,8 @@ def main(): "flightplan": process_flightplan_message, "keepalive": process_keepalive_message, "position": process_position_message, + # maybe change here + "ground_position": process_ground_position_message, } consumer = None diff --git a/fids/app.py b/fids/app.py index d6a18c6..bec01cf 100644 --- a/fids/app.py +++ b/fids/app.py @@ -48,6 +48,15 @@ UTC = timezone.utc +def _get_ground_positions(flight_id: str) -> Iterable: + return ( + positions_engine.execute( + positions.select().where(and_(positions.c.id == flight_id, positions.c.air_ground is not None)).order_by(positions.c.time.desc()) + ) + or [] + ) + + def _get_positions(flight_id: str) -> Iterable: return ( positions_engine.execute( @@ -57,6 +66,16 @@ def _get_positions(flight_id: str) -> Iterable: ) +@app.route("/ground_positions/") +def get_ground_positions(flight_id: str) -> Response: + """Get positions for a specific flight_id""" + result = _get_ground_positions(flight_id) + if not result: + abort(404) + # print("HEY HERE IS THE GROUND_POSITION DATA" + str([dict(e) for e in result])) + return jsonify([dict(e) for e in result]) + + @app.route("/positions/") def get_positions(flight_id: str) -> Response: """Get positions for a specific flight_id""" @@ -247,11 +266,28 @@ def get_map(flight_id: str) -> bytes: bearing = trig.get_cardinal_for_angle(trig.get_bearing_degrees(coord1, coord2)) coords = "|".join(f"{pos.latitude},{pos.longitude}" for pos in positions) + # Do ground positions + ground_positions = list(_get_ground_positions(flight_id)) + if not ground_positions: + abort(404) + bearing_gp = 0 + if len(ground_positions) > 1: + coord1 = (float(ground_positions[1].latitude), float(ground_positions[1].longitude)) + coord2 = (float(ground_positions[0].latitude), float(ground_positions[0].longitude)) + bearing_gp = trig.get_cardinal_for_angle(trig.get_bearing_degrees(coord1, coord2)) + coords_gp = "|".join(f"{pos.latitude},{pos.longitude}" for pos in ground_positions) + google_maps_url = "https://maps.googleapis.com/maps/api/staticmap" google_maps_params = { "size": "640x400", - "markers": f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing}.png|{positions[0].latitude},{positions[0].longitude}", - "path": f"color:0x0000ff|weight:5|{coords}", + "markers": [ + f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing}.png|{positions[0].latitude},{positions[0].longitude}", + f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing_gp}.png|{ground_positions[0].latitude},{ground_positions[0].longitude}" + ], + "path": [ + f"color:0x0000ff|weight:5|{coords}", + f"color:0xff0000|weight:5|{coords_gp}" + ], "key": google_maps_api_key, } response = requests.get(google_maps_url, google_maps_params) From b3fc07b53cf5e86a2a7d77f1d69340d1b1c83054 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 11 Aug 2022 16:59:48 -0400 Subject: [PATCH 2/6] Update db-updater/main.py Remove comments Co-authored-by: Chris Roberts --- db-updater/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/db-updater/main.py b/db-updater/main.py index 63bb99b..9a40b5e 100644 --- a/db-updater/main.py +++ b/db-updater/main.py @@ -542,7 +542,6 @@ def main(): "flightplan": process_flightplan_message, "keepalive": process_keepalive_message, "position": process_position_message, - # maybe change here "ground_position": process_ground_position_message, } From f5a50b604b4517ae2ab543a6943dcc102b2c5f39 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 11 Aug 2022 16:59:59 -0400 Subject: [PATCH 3/6] Update fids/app.py Remove testing Co-authored-by: Chris Roberts --- fids/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fids/app.py b/fids/app.py index bec01cf..125ce1b 100644 --- a/fids/app.py +++ b/fids/app.py @@ -72,7 +72,6 @@ def get_ground_positions(flight_id: str) -> Response: result = _get_ground_positions(flight_id) if not result: abort(404) - # print("HEY HERE IS THE GROUND_POSITION DATA" + str([dict(e) for e in result])) return jsonify([dict(e) for e in result]) From a0c97daf2e645811d96bd9eaf926295aca0a51b7 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 11 Aug 2022 17:00:10 -0400 Subject: [PATCH 4/6] Update fids/app.py Add comment clarification Co-authored-by: Chris Roberts --- fids/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fids/app.py b/fids/app.py index 125ce1b..d51a5a6 100644 --- a/fids/app.py +++ b/fids/app.py @@ -68,7 +68,7 @@ def _get_positions(flight_id: str) -> Iterable: @app.route("/ground_positions/") def get_ground_positions(flight_id: str) -> Response: - """Get positions for a specific flight_id""" + """Get ground positions for a specific flight_id""" result = _get_ground_positions(flight_id) if not result: abort(404) From b2cc7080ad6cd402d5293bd35494a5f3a42fe41a Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Fri, 12 Aug 2022 00:22:26 +0000 Subject: [PATCH 5/6] Add Condition for Ground Positions and Add Earliest Positions Previous check for if it was a ground_positions data point just checked if ground_air was null, now using if its value is "G". Also added functionality to get top 4 positions and return the top 2 for bearing. BCK_6624 --- fids/app.py | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/fids/app.py b/fids/app.py index d51a5a6..0c8a9fb 100644 --- a/fids/app.py +++ b/fids/app.py @@ -51,7 +51,7 @@ def _get_ground_positions(flight_id: str) -> Iterable: return ( positions_engine.execute( - positions.select().where(and_(positions.c.id == flight_id, positions.c.air_ground is not None)).order_by(positions.c.time.desc()) + positions.select().where(and_(positions.c.id == flight_id, positions.c.air_ground == "G")).order_by(positions.c.time.desc()) ) or [] ) @@ -255,33 +255,42 @@ def airport_scheduled(airport: str) -> Response: def get_map(flight_id: str) -> bytes: """Get a static map image of the specified flight. Returned as a base64-encoded image""" + def get_first_4_coords(a1, a2, b1, b2): + """ + Small function to get 4 earliest coordinates by time and return top 2 + earliest coordinates (for bearing) + """ + holder = sorted([a1, a2, b1, b2], reverse=True, key=lambda x: x.time) + return holder[:2] positions = list(_get_positions(flight_id)) if not positions: abort(404) + + # Do ground positions + ground_positions = list(_get_ground_positions(flight_id)) + do_gp = True + if not ground_positions: + do_gp = False bearing = 0 if len(positions) > 1: - coord1 = (float(positions[1].latitude), float(positions[1].longitude)) - coord2 = (float(positions[0].latitude), float(positions[0].longitude)) + if do_gp: + result = get_first_4_coords(positions[0], positions[1], ground_positions[0], ground_positions[1]) + coord1 = (float(result[1].latitude), float(result[1].longitude)) + coord2 = (float(result[0].latitude), float(result[0].longitude)) + else: + coord1 = (float(positions[1].latitude), float(positions[1].longitude)) + coord2 = (float(positions[0].latitude), float(positions[0].longitude)) bearing = trig.get_cardinal_for_angle(trig.get_bearing_degrees(coord1, coord2)) coords = "|".join(f"{pos.latitude},{pos.longitude}" for pos in positions) - # Do ground positions - ground_positions = list(_get_ground_positions(flight_id)) - if not ground_positions: - abort(404) - bearing_gp = 0 - if len(ground_positions) > 1: - coord1 = (float(ground_positions[1].latitude), float(ground_positions[1].longitude)) - coord2 = (float(ground_positions[0].latitude), float(ground_positions[0].longitude)) - bearing_gp = trig.get_cardinal_for_angle(trig.get_bearing_degrees(coord1, coord2)) - coords_gp = "|".join(f"{pos.latitude},{pos.longitude}" for pos in ground_positions) + + coords_gp = list(_get_ground_positions(flight_id)) google_maps_url = "https://maps.googleapis.com/maps/api/staticmap" google_maps_params = { "size": "640x400", "markers": [ f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing}.png|{positions[0].latitude},{positions[0].longitude}", - f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing_gp}.png|{ground_positions[0].latitude},{ground_positions[0].longitude}" ], "path": [ f"color:0x0000ff|weight:5|{coords}", From 5995fa645fc356b1ff5a7f458740211f7b2d496e Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Fri, 12 Aug 2022 01:31:55 +0000 Subject: [PATCH 6/6] Another Approach with Bearing and Fixing When trying first 4 coordinates without distingushing them between ground_positions and positions, bearing was incorrect, so just took the latest pair between the first two of the two types. Also fixed coordinate fetching so map has mix but also show plane having both positions and ground_positions distinguished. BCK_6624 --- fids/app.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/fids/app.py b/fids/app.py index 0c8a9fb..ab40e9a 100644 --- a/fids/app.py +++ b/fids/app.py @@ -255,13 +255,6 @@ def airport_scheduled(airport: str) -> Response: def get_map(flight_id: str) -> bytes: """Get a static map image of the specified flight. Returned as a base64-encoded image""" - def get_first_4_coords(a1, a2, b1, b2): - """ - Small function to get 4 earliest coordinates by time and return top 2 - earliest coordinates (for bearing) - """ - holder = sorted([a1, a2, b1, b2], reverse=True, key=lambda x: x.time) - return holder[:2] positions = list(_get_positions(flight_id)) if not positions: abort(404) @@ -274,27 +267,28 @@ def get_first_4_coords(a1, a2, b1, b2): bearing = 0 if len(positions) > 1: if do_gp: - result = get_first_4_coords(positions[0], positions[1], ground_positions[0], ground_positions[1]) - coord1 = (float(result[1].latitude), float(result[1].longitude)) - coord2 = (float(result[0].latitude), float(result[0].longitude)) + result = min(ground_positions[:2], positions[:2], key=lambda x: x[0].time) + # result = ground_positions[:2] else: - coord1 = (float(positions[1].latitude), float(positions[1].longitude)) - coord2 = (float(positions[0].latitude), float(positions[0].longitude)) + result = positions[:2] + + coord1 = (float(result[1].latitude), float(result[1].longitude)) + coord2 = (float(result[0].latitude), float(result[0].longitude)) bearing = trig.get_cardinal_for_angle(trig.get_bearing_degrees(coord1, coord2)) + else: + result = positions coords = "|".join(f"{pos.latitude},{pos.longitude}" for pos in positions) - - - coords_gp = list(_get_ground_positions(flight_id)) + gp_coords = "|".join(f"{pos.latitude},{pos.longitude}" for pos in ground_positions) google_maps_url = "https://maps.googleapis.com/maps/api/staticmap" google_maps_params = { "size": "640x400", "markers": [ - f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing}.png|{positions[0].latitude},{positions[0].longitude}", + f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing}.png|{result[0].latitude},{result[0].longitude}", ], "path": [ f"color:0x0000ff|weight:5|{coords}", - f"color:0xff0000|weight:5|{coords_gp}" + f"color:0xff0000|weight:5|{gp_coords}" if gp_coords else "", ], "key": google_maps_api_key, }