ogn-python/app/utils.py

154 wiersze
5.3 KiB
Python
Czysty Zwykły widok Historia

2015-11-11 07:03:42 +00:00
import csv
2017-10-03 11:31:24 +00:00
import gzip
2015-11-11 07:03:42 +00:00
from io import StringIO
2019-01-01 19:13:08 +00:00
from datetime import datetime, timedelta
2015-11-06 21:34:19 +00:00
2020-11-20 20:26:10 +00:00
from flask import current_app
2016-04-22 08:44:39 +00:00
from aerofiles.seeyou import Reader
2018-09-03 17:58:35 +00:00
from ogn.parser.utils import FEETS_TO_METER
2017-10-03 11:31:24 +00:00
import requests
2020-10-27 19:46:14 +00:00
from .model import AircraftType, SenderInfoOrigin, SenderInfo, Airport, Location
2016-04-22 08:44:39 +00:00
2016-05-31 18:56:09 +00:00
DDB_URL = "http://ddb.glidernet.org/download/?t=1"
2018-10-21 15:34:03 +00:00
FLARMNET_URL = "http://www.flarmnet.org/files/data.fln"
2015-11-06 21:34:19 +00:00
2015-11-15 07:51:40 +00:00
2019-08-31 08:14:41 +00:00
address_prefixes = {"F": "FLR", "O": "OGN", "I": "ICA"}
2015-12-01 18:11:31 +00:00
2016-04-22 08:44:39 +00:00
nm2m = 1852
mi2m = 1609.34
2015-11-06 21:34:19 +00:00
2019-01-01 19:13:08 +00:00
def get_days(start, end):
days = [start + timedelta(days=x) for x in range(0, (end - start).days + 1)]
return days
def date_to_timestamps(date):
start = datetime(date.year, date.month, date.day, 0, 0, 0)
end = datetime(date.year, date.month, date.day, 23, 59, 59)
return (start, end)
2020-10-27 19:46:14 +00:00
def get_ddb(csv_file=None, address_origin=SenderInfoOrigin.UNKNOWN):
2018-10-21 15:34:03 +00:00
if csv_file is None:
2015-11-11 07:03:42 +00:00
r = requests.get(DDB_URL)
2019-08-31 08:14:41 +00:00
rows = "\n".join(i for i in r.text.splitlines() if i[0] != "#")
2015-11-11 07:03:42 +00:00
else:
2019-08-31 08:14:41 +00:00
r = open(csv_file, "r")
rows = "".join(i for i in r.readlines() if i[0] != "#")
2015-11-11 07:03:42 +00:00
data = csv.reader(StringIO(rows), quotechar="'", quoting=csv.QUOTE_ALL)
2015-11-06 21:34:19 +00:00
2020-10-27 19:46:14 +00:00
sender_infos = list()
2015-11-11 07:03:42 +00:00
for row in data:
2020-10-27 19:46:14 +00:00
sender_info = SenderInfo()
sender_info.address_type = row[0]
sender_info.address = row[1]
sender_info.aircraft = row[2]
sender_info.registration = row[3]
sender_info.competition = row[4]
sender_info.tracked = row[5] == "Y"
sender_info.identified = row[6] == "Y"
sender_info.aircraft_type = AircraftType(int(row[7]))
sender_info.address_origin = address_origin
2016-06-21 17:34:05 +00:00
2020-10-27 19:46:14 +00:00
sender_infos.append(sender_info)
2016-06-21 17:34:05 +00:00
2020-10-27 19:46:14 +00:00
return sender_infos
2015-11-06 21:34:19 +00:00
2018-11-28 06:37:35 +00:00
2020-10-27 19:46:14 +00:00
def get_flarmnet(fln_file=None, address_origin=SenderInfoOrigin.FLARMNET):
2018-10-21 15:34:03 +00:00
if fln_file is None:
r = requests.get(FLARMNET_URL)
2020-10-27 19:46:14 +00:00
rows = [bytes.fromhex(line).decode("latin1") for line in r.text.split("\n") if len(line) == 173]
2018-10-21 15:34:03 +00:00
else:
2019-08-31 08:14:41 +00:00
with open(fln_file, "r") as file:
2020-10-27 19:46:14 +00:00
rows = [bytes.fromhex(line.strip()).decode("latin1") for line in file.readlines() if len(line) == 173]
2018-11-28 06:37:35 +00:00
2020-10-27 19:46:14 +00:00
sender_infos = list()
2018-10-21 15:34:03 +00:00
for row in rows:
2020-10-27 19:46:14 +00:00
sender_info = SenderInfo()
sender_info.address = row[0:6].strip()
sender_info.aircraft = row[48:69].strip()
sender_info.registration = row[69:76].strip()
sender_info.competition = row[76:79].strip()
2018-11-28 06:37:35 +00:00
2020-10-27 19:46:14 +00:00
sender_infos.append(sender_info)
2018-10-21 15:34:03 +00:00
2020-10-27 19:46:14 +00:00
return sender_infos
2015-11-06 21:34:19 +00:00
2018-11-28 06:37:35 +00:00
2015-12-01 18:11:31 +00:00
def get_trackable(ddb):
2019-01-01 19:13:08 +00:00
result = []
2016-01-05 23:23:45 +00:00
for i in ddb:
if i.tracked and i.address_type in address_prefixes:
2019-01-01 19:13:08 +00:00
result.append("{}{}".format(address_prefixes[i.address_type], i.address))
return result
2015-12-01 18:11:31 +00:00
2018-11-28 06:37:35 +00:00
2016-04-22 08:44:39 +00:00
def get_airports(cupfile):
airports = list()
with open(cupfile) as f:
for line in f:
try:
for waypoint in Reader([line]):
2019-08-31 08:14:41 +00:00
if waypoint["style"] > 5: # reject unlandable places
2016-05-22 05:26:02 +00:00
continue
2016-04-22 08:44:39 +00:00
airport = Airport()
2019-08-31 08:14:41 +00:00
airport.name = waypoint["name"]
airport.code = waypoint["code"]
airport.country_code = waypoint["country"]
airport.style = waypoint["style"]
airport.description = waypoint["description"]
location = Location(waypoint["longitude"], waypoint["latitude"])
airport.location_wkt = location.to_wkt()
2019-08-31 08:14:41 +00:00
airport.altitude = waypoint["elevation"]["value"]
if waypoint["elevation"]["unit"] == "ft":
2018-09-03 17:58:35 +00:00
airport.altitude = airport.altitude * FEETS_TO_METER
2019-08-31 08:14:41 +00:00
airport.runway_direction = waypoint["runway_direction"]
airport.runway_length = waypoint["runway_length"]["value"]
if waypoint["runway_length"]["unit"] == "nm":
airport.altitude = airport.altitude * nm2m
2019-08-31 08:14:41 +00:00
elif waypoint["runway_length"]["unit"] == "ml":
airport.altitude = airport.altitude * mi2m
2019-08-31 08:14:41 +00:00
airport.frequency = waypoint["frequency"]
2016-04-22 08:44:39 +00:00
airports.append(airport)
except AttributeError as e:
2020-11-20 20:26:10 +00:00
current_app.logger.error("Failed to parse line: {} {}".format(line, e))
2016-04-22 08:44:39 +00:00
return airports
def open_file(filename):
"""Opens a regular or unzipped textfile for reading."""
2019-08-31 08:14:41 +00:00
f = open(filename, "rb")
a = f.read(2)
f.close()
2019-08-31 08:14:41 +00:00
if a == b"\x1f\x8b":
f = gzip.open(filename, "rt", encoding="latin-1")
return f
else:
2019-08-31 08:14:41 +00:00
f = open(filename, "rt", encoding="latin-1")
return f
2020-10-27 19:46:14 +00:00
2020-11-22 07:55:19 +00:00
2020-10-27 19:46:14 +00:00
def get_sql_trustworthy(source_table_alias):
2020-11-22 07:55:19 +00:00
MIN_DISTANCE = 1000
2020-10-27 19:46:14 +00:00
MAX_DISTANCE = 640000
MAX_NORMALIZED_QUALITY = 40 # this is enough for > 640km
MAX_ERROR_COUNT = 5
MAX_CLIMB_RATE = 50
return f"""
({source_table_alias}.distance IS NOT NULL AND {source_table_alias}.distance BETWEEN {MIN_DISTANCE} AND {MAX_DISTANCE})
AND ({source_table_alias}.normalized_quality IS NOT NULL AND {source_table_alias}.normalized_quality < {MAX_NORMALIZED_QUALITY})
AND ({source_table_alias}.error_count IS NULL OR {source_table_alias}.error_count < {MAX_ERROR_COUNT})
AND ({source_table_alias}.climb_rate IS NULL OR {source_table_alias}.climb_rate BETWEEN -{MAX_CLIMB_RATE} AND {MAX_CLIMB_RATE})
2020-11-22 07:55:19 +00:00
"""