From d39b404f6279075592dbf9f943b7caf505b12283 Mon Sep 17 00:00:00 2001 From: Jack Sweeney Date: Thu, 9 Jun 2022 18:15:54 -0400 Subject: [PATCH] TFRs toggle, pounds fix, photo override fix -TFRS toggle -Pounds fix -Photo override fix - Airport code on image fix -TFR above/below addition --- configs/mainconf.ini | 1 + defSS.py | 10 +- fuel_calc.py | 8 +- modify_image.py | 9 +- planeClass.py | 234 ++++++++++++++++++++++--------------------- 5 files changed, 138 insertions(+), 124 deletions(-) diff --git a/configs/mainconf.ini b/configs/mainconf.ini index 5c0619f..1ea437c 100644 --- a/configs/mainconf.ini +++ b/configs/mainconf.ini @@ -40,6 +40,7 @@ URL = webhookurl [TFRS] URL = http://127.0.0.1:5000/detailed_all +ENABLE = False [TWITTER] #GLOBAL TWITTER CONSUMER KEY AND CONSUMERS SECRET ONLY NEED TO BE HERE NOW diff --git a/defSS.py b/defSS.py index 66da583..67f1783 100644 --- a/defSS.py +++ b/defSS.py @@ -80,16 +80,20 @@ def get_adsbx_screenshot(file_path, url_params, enable_labels=False, enable_trac photo_box = browser.find_element_by_id("airplanePhoto") finally: import requests, json - photo_list = json.loads(requests.get("https://raw.githubusercontent.com/Jxck-S/aircraft-photos/main/photo-list.json").text) + photo_list = json.loads(requests.get("https://raw.githubusercontent.com/Jxck-S/aircraft-photos/main/photo-list.json", timeout=20).text) if reg in photo_list.keys(): browser.execute_script("arguments[0].id = 'airplanePhoto';", photo_box) browser.execute_script("arguments[0].removeAttribute('width')", photo_box) - browser.execute_script("arguments[0].style.width = 'inherit';", photo_box) + browser.execute_script("arguments[0].style.width = '200px';", photo_box) browser.execute_script("arguments[0].style.float = 'left';", photo_box) browser.execute_script(f"arguments[0].src = 'https://raw.githubusercontent.com/Jxck-S/aircraft-photos/main/images/{reg}.jpg';", photo_box) image_copy_right = browser.find_element_by_id("copyrightInfo") browser.execute_cdp_cmd('Emulation.setScriptExecutionDisabled', {'value': True}) - browser.execute_script(f"arguments[0].appendChild(document.createTextNode('Image © {photo_list[reg]['photographer']}'))", image_copy_right) + copy_right_children = image_copy_right.find_elements(By.XPATH, "*") + if len(copy_right_children) > 0: + browser.execute_script(f"arguments[0].innerText = 'Image © {photo_list[reg]['photographer']}'", copy_right_children[0]) + else: + browser.execute_script(f"arguments[0].appendChild(document.createTextNode('Image © {photo_list[reg]['photographer']}'))", image_copy_right) except Exception as e: print("Error on changing photo", e) if 'type' in overrides.keys(): diff --git a/fuel_calc.py b/fuel_calc.py index d5c95ba..4dec4e0 100644 --- a/fuel_calc.py +++ b/fuel_calc.py @@ -31,7 +31,7 @@ def fuel_calculation(aircraft_icao_type, minutes): fuel_flight_info['fuel_used_kg'] = round(fuel_used_kg) fuel_flight_info["fuel_used_gal"] = round(fuel_used_gal) fuel_flight_info['fuel_used_lters'] = round(fuel_used_gal*3.78541) - fuel_flight_info["fuel_used_pds"] = round(fuel_used_kg * 2.20462) + fuel_flight_info["fuel_used_lbs"] = round(fuel_used_kg * 2.20462) fuel_flight_info["c02_tons"] = c02_tons print ("Fuel info", fuel_flight_info) return fuel_flight_info @@ -43,10 +43,10 @@ def fuel_message(fuel_info): cost = "{:,}".format(fuel_info['fuel_price']) gallons = "{:,}".format(fuel_info['fuel_used_gal']) lters = "{:,}".format(fuel_info['fuel_used_lters']) - pds = "{:,}".format(fuel_info['fuel_used_pds']) + lbs = "{:, }".format(fuel_info['fuel_used_lbs']) kgs = "{:,}".format(fuel_info['fuel_used_kg']) - fuel_message = f"~ {gallons} gallons ({lters} liters). \n~ {pds} pds ({kgs} kg) of jet fuel used. \n~ ${cost} cost of fuel. \n~ {fuel_info['c02_tons']} tons of CO2 emissions." + fuel_message = f"~ {gallons} gallons ({lters} liters). \n~ {lbs} lbs ({kgs} kg) of jet fuel used. \n~ ${cost} cost of fuel. \n~ {fuel_info['c02_tons']} tons of CO2 emissions." print(fuel_message) return fuel_message -#fuel_info = fuel_calculation("B738", 180) +#fuel_info = fuel_calculation("GLF6", 548.1) #fuel_message(fuel_info) diff --git a/modify_image.py b/modify_image.py index 9db6e81..1690193 100644 --- a/modify_image.py +++ b/modify_image.py @@ -44,8 +44,13 @@ def append_airport(filename, airport, text_credit=None): draw.text((x, y), text, fill=white, font=head_font) #ICAO | IATA (x, y) = (330, 765) - text = iata + " / " + icao - draw.text((x, y), text, fill=black, font=font) + if airport['iata_code'] != '' and airport['icao'] != '': + airport_codes = airport['iata_code'] + " / " + airport['icao'] + elif airport['icao'] != '': + airport_codes = airport['icao'] + else: + airport_codes = airport['ident'] + draw.text((x, y), airport_codes, fill=black, font=font) #Distance (x, y) = (460, 765) text = str(round(distance_mi, 2)) + "mi / " + str(round(distance_km, 2)) + "km away" diff --git a/planeClass.py b/planeClass.py index 52b9988..dd8f62f 100644 --- a/planeClass.py +++ b/planeClass.py @@ -485,7 +485,7 @@ class Plane: to_coord = (known_to_airport['latitude_deg'], known_to_airport['longitude_deg']) distance_mi = float(geodesic(from_coord, to_coord).mi) distance_nm = distance_mi / 1.150779448 - distance_message = f"{'{:,}'.format(round(distance_mi))} mile ({'{:,}'.format(round(distance_nm))} NM) flight from {nearest_from_airport['iata_code']} to {nearest_airport_dict['iata_code']}\n" + distance_message = f"{'{:,}'.format(round(distance_mi))} mile ({'{:,}'.format(round(distance_nm))} NM) flight from {nearest_from_airport['iata_code'] if nearest_from_airport['iata_code'] != '' else nearest_from_airport['ident']} to {nearest_airport_dict['iata_code'] if nearest_airport_dict['iata_code'] != '' else nearest_airport_dict['ident']}\n" else: distance_message = "" if landed_time is not None and self.type is not None: @@ -644,121 +644,124 @@ class Plane: from shapely.geometry.polygon import Polygon from shapely.geometry import Point import requests, json - tfr_url = Plane.main_config.get("TFRS", "URL") - response = requests.get(tfr_url, timeout=30) - tfrs = json.loads(response.text) closest_tfr = None in_tfr = None - for tfr in tfrs: - if in_tfr is not None: - break - elif tfr['details'] is not None and 'shapes' in tfr['details'].keys(): - for index, shape in enumerate(tfr['details']['shapes']): - if 'txtName' not in shape.keys(): - shape['txtName'] = 'shape_'+str(index) - polygon = None - if shape['type'] == "poly": - points = shape['points'] - elif shape['type'] == "circle": - from functools import partial - import pyproj - from shapely.ops import transform - from shapely.geometry import Point - proj_wgs84 = pyproj.Proj('+proj=longlat +datum=WGS84') - def geodesic_point_buffer(lat, lon, km): - # Azimuthal equidistant projection - aeqd_proj = '+proj=aeqd +lat_0={lat} +lon_0={lon} +x_0=0 +y_0=0' - project = partial( - pyproj.transform, - pyproj.Proj(aeqd_proj.format(lat=lat, lon=lon)), - proj_wgs84) - buf = Point(0, 0).buffer(km * 1000) # distance in metres - return transform(project, buf).exterior.coords[:] - radius_km = float(shape['radius']) * 1.852 - b = geodesic_point_buffer(shape['lat'], shape['lon'], radius_km) - points = [] - for coordinate in b: - points.append([coordinate[1], coordinate[0]]) - elif shape['type'] in ["polyarc", "polyexclude"]: - points = shape['all_points'] - aircraft_location = Point(self.latitude, self.longitude) - if polygon is None: - polygon = Polygon(points) - if polygon.contains(aircraft_location): - in_tfr = {'info': tfr, 'closest_shape_name' : shape['txtName']} - break - else: - point_dists = [] - for point in points: - from geopy.distance import geodesic - point = tuple(point) - point_dists.append(float((geodesic((self.latitude, self.longitude), point).mi))) - distance = min(point_dists) - if closest_tfr is None: - closest_tfr = {'info': tfr, 'closest_shape_name' : shape['txtName'], 'distance' : round(distance)} - elif distance < closest_tfr['distance']: - closest_tfr = {'info': tfr, 'closest_shape_name' : shape['txtName'], 'distance' : round(distance)} - if in_tfr is not None: - for shape in in_tfr['info']['details']['shapes']: - if shape['txtName'] == in_tfr['closest_shape_name']: - valDistVerUpper, valDistVerLower = int(shape['valDistVerUpper']), int(shape['valDistVerLower']) - print("In TFR based off location checking alt next", in_tfr) + if Plane.main_config.getboolean("TFRS", "ENABLE"): + tfr_url = Plane.main_config.get("TFRS", "URL") + response = requests.get(tfr_url, timeout=30) + tfrs = json.loads(response.text) + for tfr in tfrs: + if in_tfr is not None: break - if not (self.alt_ft >= valDistVerLower and self.alt_ft <= valDistVerUpper): - print("But not in alt of TFR") - closest_tfr = in_tfr - closest_tfr['distance'] = 0 - in_tfr = None - if in_tfr is None: - print("Closest TFR", closest_tfr) - #Generate Map - import staticmaps - context = staticmaps.Context() - context.set_tile_provider(staticmaps.tile_provider_OSM) - if in_tfr is not None: - shapes = in_tfr['info']['details']['shapes'] - else: - shapes = closest_tfr['info']['details']['shapes'] - def draw_poly(context, pairs): - pairs.append(pairs[0]) - context.add_object( - staticmaps.Area( - [staticmaps.create_latlng(lat, lng) for lat, lng in pairs], - fill_color=staticmaps.parse_color("#FF000033"), - width=2, - color=staticmaps.parse_color("#8B0000"), + elif tfr['details'] is not None and 'shapes' in tfr['details'].keys(): + for index, shape in enumerate(tfr['details']['shapes']): + if 'txtName' not in shape.keys(): + shape['txtName'] = 'shape_'+str(index) + polygon = None + if shape['type'] == "poly": + points = shape['points'] + elif shape['type'] == "circle": + from functools import partial + import pyproj + from shapely.ops import transform + from shapely.geometry import Point + proj_wgs84 = pyproj.Proj('+proj=longlat +datum=WGS84') + def geodesic_point_buffer(lat, lon, km): + # Azimuthal equidistant projection + aeqd_proj = '+proj=aeqd +lat_0={lat} +lon_0={lon} +x_0=0 +y_0=0' + project = partial( + pyproj.transform, + pyproj.Proj(aeqd_proj.format(lat=lat, lon=lon)), + proj_wgs84) + buf = Point(0, 0).buffer(km * 1000) # distance in metres + return transform(project, buf).exterior.coords[:] + radius_km = float(shape['radius']) * 1.852 + b = geodesic_point_buffer(shape['lat'], shape['lon'], radius_km) + points = [] + for coordinate in b: + points.append([coordinate[1], coordinate[0]]) + elif shape['type'] in ["polyarc", "polyexclude"]: + points = shape['all_points'] + aircraft_location = Point(self.latitude, self.longitude) + if polygon is None: + polygon = Polygon(points) + if polygon.contains(aircraft_location): + in_tfr = {'info': tfr, 'closest_shape_name' : shape['txtName']} + break + else: + point_dists = [] + for point in points: + from geopy.distance import geodesic + point = tuple(point) + point_dists.append(float((geodesic((self.latitude, self.longitude), point).mi))) + distance = min(point_dists) + if closest_tfr is None: + closest_tfr = {'info': tfr, 'closest_shape_name' : shape['txtName'], 'distance' : round(distance)} + elif distance < closest_tfr['distance']: + closest_tfr = {'info': tfr, 'closest_shape_name' : shape['txtName'], 'distance' : round(distance)} + if in_tfr is not None: + for shape in in_tfr['info']['details']['shapes']: + if shape['txtName'] == in_tfr['closest_shape_name']: + valDistVerUpper, valDistVerLower = int(shape['valDistVerUpper']), int(shape['valDistVerLower']) + print("In TFR based off location checking alt next", in_tfr) + break + if not (self.alt_ft >= valDistVerLower and self.alt_ft <= valDistVerUpper): + if self.alt_ft > valDistVerUpper: + in_tfr['context'] = "above" + elif self.alt_ft < valDistVerLower: + in_tfr['context'] = "below" + print("But not in alt of TFR", in_tfr['context']) + + if in_tfr is None: + print("Closest TFR", closest_tfr) + #Generate Map + import staticmaps + context = staticmaps.Context() + context.set_tile_provider(staticmaps.tile_provider_OSM) + if in_tfr is not None: + shapes = in_tfr['info']['details']['shapes'] + else: + shapes = closest_tfr['info']['details']['shapes'] + def draw_poly(context, pairs): + pairs.append(pairs[0]) + context.add_object( + staticmaps.Area( + [staticmaps.create_latlng(lat, lng) for lat, lng in pairs], + fill_color=staticmaps.parse_color("#FF000033"), + width=2, + color=staticmaps.parse_color("#8B0000"), + ) ) - ) - return context - for shape in shapes: - if shape['type'] == "poly": - pairs = shape['points'] - context = draw_poly(context, pairs) - elif shape['type'] == "polyarc" or shape['type'] == "polyexclude": - pairs = shape['all_points'] - context = draw_poly(context, pairs) - elif shape['type'] =="circle": - center = [shape['lat'], shape['lon']] - center1 = staticmaps.create_latlng(center[0], center[1]) - context.add_object(staticmaps.Circle(center1, (float(shape['radius']) * 1.852), fill_color=staticmaps.parse_color("#FF000033"), color=staticmaps.parse_color("#8B0000"), width=2)) - context.add_object(staticmaps.Marker(center1, color=staticmaps.RED)) - def tfr_image(context, aircraft_coords): - from PIL import Image - heading = self.track - heading *= -1 - im = Image.open('./dependencies/ac.png') - im_rotate = im.rotate(heading, resample=Image.BICUBIC) - import tempfile - rotated_file = f"{tempfile.gettempdir()}/rotated_ac.png" - im_rotate.save(rotated_file) - pos = staticmaps.create_latlng(aircraft_coords[0], aircraft_coords[1]) - marker = staticmaps.ImageMarker(pos, rotated_file, origin_x=35, origin_y=35) - context.add_object(marker) - image = context.render_cairo(1000, 1000) - os.remove(rotated_file) - tfr_map_filename = f"{tempfile.gettempdir()}/{self.icao}_TFR_.png" - image.write_to_png(tfr_map_filename) - return tfr_map_filename + return context + for shape in shapes: + if shape['type'] == "poly": + pairs = shape['points'] + context = draw_poly(context, pairs) + elif shape['type'] == "polyarc" or shape['type'] == "polyexclude": + pairs = shape['all_points'] + context = draw_poly(context, pairs) + elif shape['type'] =="circle": + center = [shape['lat'], shape['lon']] + center1 = staticmaps.create_latlng(center[0], center[1]) + context.add_object(staticmaps.Circle(center1, (float(shape['radius']) * 1.852), fill_color=staticmaps.parse_color("#FF000033"), color=staticmaps.parse_color("#8B0000"), width=2)) + context.add_object(staticmaps.Marker(center1, color=staticmaps.RED)) + def tfr_image(context, aircraft_coords): + from PIL import Image + heading = self.track + heading *= -1 + im = Image.open('./dependencies/ac.png') + im_rotate = im.rotate(heading, resample=Image.BICUBIC) + import tempfile + rotated_file = f"{tempfile.gettempdir()}/rotated_ac.png" + im_rotate.save(rotated_file) + pos = staticmaps.create_latlng(aircraft_coords[0], aircraft_coords[1]) + marker = staticmaps.ImageMarker(pos, rotated_file, origin_x=35, origin_y=35) + context.add_object(marker) + image = context.render_cairo(1000, 1000) + os.remove(rotated_file) + tfr_map_filename = f"{tempfile.gettempdir()}/{self.icao}_TFR_.png" + image.write_to_png(tfr_map_filename) + return tfr_map_filename from defSS import get_adsbx_screenshot @@ -773,12 +776,13 @@ class Plane: message = f"Circling {round(nearest_airport_dict['distance_mi'], 2)}mi {cardinal} of {nearest_airport_dict['icao']}, {nearest_airport_dict['name']} at {self.alt_ft}ft. " tfr_map_filename = None if in_tfr is not None: - message += f" Inside TFR {in_tfr['info']['NOTAM']}, a TFR for {in_tfr['info']['Type'].title()}" + context = "Inside" if 'context' not in in_tfr.keys() else "Above" if in_tfr['context'] == 'above' else "Below" + message += f" {context} TFR {in_tfr['info']['NOTAM']}, a TFR for {in_tfr['info']['Type'].title()}" tfr_map_filename = tfr_image(context, (self.latitude, self.longitude)) - elif in_tfr is None and "distance" in closest_tfr.keys() and closest_tfr["distance"] <= 20: + elif in_tfr is None and closest_tfr is not None and "distance" in closest_tfr.keys() and closest_tfr["distance"] <= 20: message += f" {closest_tfr['distance']} miles from TFR {closest_tfr['info']['NOTAM']}, a TFR for {closest_tfr['info']['Type']}" tfr_map_filename = tfr_image(context, (self.latitude, self.longitude)) - elif in_tfr is None and "distance" not in closest_tfr.keys(): + elif in_tfr is None and closest_tfr is not None and "distance" not in closest_tfr.keys(): message += f" near TFR {closest_tfr['info']['NOTAM']}, a TFR for {closest_tfr['info']['Type']}" raise Exception(message)