Merge branch 'rapidapi' of https://github.com/makrsmark/plane-notify into rapidapi
This commit is contained in:
commit
4f1ec7e278
|
@ -15,11 +15,11 @@ Notify if configured planes have taken off or landed using Python with <a href="
|
|||
|
||||
### Background
|
||||
|
||||
I made this program so I could track Elon Musk's Jet and share with others of his whereabouts on Twitter. [](https://twitter.com/ElonJet) I have now Expanded and run multiple accounts for multiple planes, a list of the accounts here [plane-notify Twitter List](https://twitter.com/i/lists/1307414615316467715)
|
||||
I made this program so I could track Elon Musk's Jet and share his whereabouts with others on Twitter. [](https://twitter.com/ElonJet) I have now expanded and run multiple accounts for multiple planes, a list of the accounts can be found here [plane-notify Twitter List](https://twitter.com/i/lists/1307414615316467715)
|
||||
|
||||
### Contributing
|
||||
|
||||
I'm open to any help or suggestions, I realize there are many better ways to improve this program and better ways to get this program to work properly, Im only a noob. I'll accept pull requests. If you'd like to discuss join <https://JacksTech.net/Discord>
|
||||
I'm open to any help or suggestions, I realize there are many better ways to improve this program and better ways to get this program to work properly, I'm only a noob. I'll accept pull requests. If you'd like to discuss join <https://JacksTech.net/Discord>
|
||||
|
||||
### [Algorithm](PseudoCode.md)
|
||||
|
||||
|
|
|
@ -45,4 +45,14 @@ API_KEY = googleapikey
|
|||
[DISCORD]
|
||||
ENABLE = FALSE
|
||||
USERNAME = usernamehere
|
||||
URL = webhookurl
|
||||
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
|
||||
ENABLE = False
|
||||
CONSUMER_KEY = ck
|
||||
CONSUMER_SECRET = cs
|
||||
|
|
|
@ -7,6 +7,7 @@ ICAO = icaohere
|
|||
; OVERRIDE_REG=
|
||||
; OVERRIDE_ICAO_TYPE=
|
||||
; OVERRIDE_TYPELONG =
|
||||
; OVERRIDE_OWNER =
|
||||
; DATA_LOSS_MINS = 20
|
||||
|
||||
[MAP]
|
||||
|
|
33
defSS.py
33
defSS.py
|
@ -5,6 +5,7 @@ from webdriver_manager.chrome import ChromeDriverManager
|
|||
import time
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.common.exceptions import NoSuchElementException
|
||||
|
||||
def get_adsbx_screenshot(file_path, url_params, enable_labels=False, enable_track_labels=False, overrides={}):
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
|
@ -67,30 +68,32 @@ def get_adsbx_screenshot(file_path, url_params, enable_labels=False, enable_trac
|
|||
else:
|
||||
try:
|
||||
reg = browser.find_element_by_id("selected_registration").get_attribute("innerHTML")
|
||||
print(reg)
|
||||
print("Reg from tar1090 is", reg)
|
||||
except Exception as e:
|
||||
print("Couldn't find reg in tar1090", e)
|
||||
reg = None
|
||||
if reg is not None:
|
||||
try:
|
||||
try:
|
||||
myElem = WebDriverWait(browser, 150).until(EC.presence_of_element_located((By.ID, 'silhouette')))
|
||||
photo_box = browser.find_element_by_id("silhouette")
|
||||
except:
|
||||
except NoSuchElementException:
|
||||
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(f"arguments[0].src = 'https://raw.githubusercontent.com/Jxck-S/aircraft-photos/main/images/{reg}.jpg';", photo_box)
|
||||
copyright = browser.find_element_by_id("copyrightInfo")
|
||||
browser.execute_script("arguments[0].id = 'copyrightInfoFreeze';", copyright)
|
||||
browser.execute_script("$('#copyrightInfoFreeze').css('font-size', '12px');")
|
||||
#browser.execute_script("""var element = arguments[0];
|
||||
#element.parentNode.removeChild(element.firstChild);""", copyright)
|
||||
browser.execute_script(f"arguments[0].appendChild(document.createTextNode('Image © {photo_list[reg]['photographer']}'))", copyright)
|
||||
|
||||
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 = '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})
|
||||
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():
|
||||
|
@ -99,9 +102,11 @@ def get_adsbx_screenshot(file_path, url_params, enable_labels=False, enable_trac
|
|||
if 'typelong' in overrides.keys():
|
||||
element = browser.find_element_by_id("selected_typelong")
|
||||
browser.execute_script(f"arguments[0].innerText = '* {overrides['typelong']}'", element)
|
||||
if 'ownop' in overrides.keys():
|
||||
element = browser.find_element_by_id("selected_ownop")
|
||||
browser.execute_script(f"arguments[0].innerText = '* {overrides['ownop']}'", element)
|
||||
time.sleep(5)
|
||||
browser.save_screenshot(file_path)
|
||||
browser.quit()
|
||||
def generate_adsbx_screenshot_time_params(timestamp):
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
278
planeClass.py
278
planeClass.py
|
@ -7,8 +7,22 @@ class Plane:
|
|||
"""Initializes a plane object from its config file and given icao."""
|
||||
self.icao = icao.upper()
|
||||
self.callsign = None
|
||||
self.reg = None
|
||||
self.config = config
|
||||
self.overrides = {}
|
||||
if self.config.has_option('DATA', 'OVERRIDE_REG'):
|
||||
self.reg = self.config.get('DATA', 'OVERRIDE_REG')
|
||||
self.overrides['reg'] = self.reg
|
||||
else:
|
||||
self.reg = None
|
||||
if self.config.has_option('DATA', 'OVERRIDE_ICAO_TYPE'):
|
||||
self.type = self.config.get('DATA', 'OVERRIDE_ICAO_TYPE')
|
||||
self.overrides['type'] = self.type
|
||||
else:
|
||||
self.type = None
|
||||
if self.config.has_option('DATA', 'OVERRIDE_ICAO_TYPE'):
|
||||
self.overrides['typelong'] = self.config.get('DATA', 'OVERRIDE_TYPELONG')
|
||||
if self.config.has_option('DATA', 'OVERRIDE_OWNER'):
|
||||
self.overrides['ownop'] = self.config.get('DATA', 'OVERRIDE_OWNER')
|
||||
self.conf_file_path = config_path
|
||||
self.alt_ft = None
|
||||
self.below_desired_ft = None
|
||||
|
@ -41,7 +55,6 @@ class Plane:
|
|||
self.track = None
|
||||
self.last_track = None
|
||||
self.circle_history = None
|
||||
self.type = None
|
||||
if self.config.has_option('DATA', 'DATA_LOSS_MINS'):
|
||||
self.data_loss_mins = self.config.getint('DATA', 'DATA_LOSS_MINS')
|
||||
else:
|
||||
|
@ -67,7 +80,7 @@ class Plane:
|
|||
self.print_header("BEGIN")
|
||||
#print (Fore.YELLOW + "OpenSky Sourced Data: ", ac_dict)
|
||||
try:
|
||||
self.__dict__.update({'icao' : ac_dict.icao24.upper(), 'callsign' : ac_dict.callsign, 'latitude' : ac_dict.latitude, 'longitude' : ac_dict.longitude, 'on_ground' : bool(ac_dict.on_ground), 'squawk' : ac_dict.squawk, 'track' : float(ac_dict.true_track)})
|
||||
self.__dict__.update({'icao' : ac_dict.icao24.upper(), 'callsign' : ac_dict.callsign, 'latitude' : ac_dict.latitude, 'longitude' : ac_dict.longitude, 'on_ground' : bool(ac_dict.on_ground), 'squawk' : ac_dict.squawk, 'track' : float(ac_dict.heading)})
|
||||
if ac_dict.baro_altitude != None:
|
||||
self.alt_ft = round(float(ac_dict.baro_altitude) * 3.281)
|
||||
elif self.on_ground:
|
||||
|
@ -75,8 +88,9 @@ class Plane:
|
|||
from mictronics_parse import get_aircraft_reg_by_icao, get_type_code_by_icao
|
||||
self.reg = get_aircraft_reg_by_icao(self.icao)
|
||||
self.type = get_type_code_by_icao(self.icao)
|
||||
self.last_pos_datetime = datetime.fromtimestamp(ac_dict.time_position)
|
||||
except Exception as e:
|
||||
if ac_dict.time_position is not None:
|
||||
self.last_pos_datetime = datetime.fromtimestamp(ac_dict.time_position)
|
||||
except ValueError as e:
|
||||
print("Got data but some data is invalid!")
|
||||
print(e)
|
||||
self.print_header("END")
|
||||
|
@ -423,8 +437,8 @@ class Plane:
|
|||
getMap((municipality + ", " + state + ", " + country_code), self.map_file_name)
|
||||
elif Plane.main_config.get('MAP', 'OPTION') == "ADSBX":
|
||||
from defSS import get_adsbx_screenshot
|
||||
url_params = f"icao={self.icao}&zoom=9&largeMode=2&hideButtons&hideSidebar&mapDim=0&overlays=" + self.get_adsbx_map_overlays()
|
||||
get_adsbx_screenshot(self.map_file_name, url_params)
|
||||
url_params = f"largeMode=2&hideButtons&hideSidebar&mapDim=0&zoom=10&icao={self.icao}&overlays={self.get_adsbx_map_overlays()}"
|
||||
get_adsbx_screenshot(self.map_file_name, url_params, overrides=self.overrides)
|
||||
from modify_image import append_airport
|
||||
text_credit = self.config.get('MAP', 'TEXT_CREDIT') if self.config.has_option('MAP', 'TEXT_CREDIT') else None
|
||||
append_airport(self.map_file_name, nearest_airport_dict, text_credit)
|
||||
|
@ -472,7 +486,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:
|
||||
|
@ -545,8 +559,8 @@ class Plane:
|
|||
getMap((municipality + ", " + state + ", " + country_code), self.map_file_name)
|
||||
if Plane.main_config.get('MAP', 'OPTION') == "ADSBX":
|
||||
from defSS import get_adsbx_screenshot
|
||||
url_params = f"icao={self.icao}&zoom=9&largeMode=2&hideButtons&hideSidebar&mapDim=0&overlays=" + self.get_adsbx_map_overlays()
|
||||
get_adsbx_screenshot(self.map_file_name, url_params)
|
||||
url_params = f"largeMode=2&hideButtons&hideSidebar&mapDim=0&zoom=10&icao={self.icao}&overlays={self.get_adsbx_map_overlays()}"
|
||||
get_adsbx_screenshot(self.map_file_name, url_params, overrides=self.overrides)
|
||||
if self.config.getboolean('DISCORD', 'ENABLE'):
|
||||
dis_message = (self.dis_title + " " + squawk_message)
|
||||
sendDis(dis_message, self.config, None, self.map_file_name)
|
||||
|
@ -568,8 +582,8 @@ class Plane:
|
|||
dis_message = (self.dis_title + " " + mode + " mode enabled.")
|
||||
if mode == "Approach":
|
||||
from defSS import get_adsbx_screenshot
|
||||
url_params = f"icao={self.icao}&zoom=9&largeMode=2&hideButtons&hideSidebar&mapDim=0&overlays={self.get_adsbx_map_overlays()}"
|
||||
get_adsbx_screenshot(self.map_file_name, url_params)
|
||||
url_params = f"largeMode=2&hideButtons&hideSidebar&mapDim=0&zoom=10&icao={self.icao}&overlays={self.get_adsbx_map_overlays()}"
|
||||
get_adsbx_screenshot(self.map_file_name, url_params, overrides=self.overrides)
|
||||
sendDis(dis_message, self.config, None, self.map_file_name)
|
||||
#elif mode in ["Althold", "VNAV", "LNAV"] and self.sel_nav_alt != None:
|
||||
# sendDis((dis_message + ", Sel Alt. " + str(self.sel_nav_alt) + ", Current Alt. " + str(self.alt_ft)), self.config)
|
||||
|
@ -631,125 +645,128 @@ 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=60)
|
||||
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
|
||||
url_params = f"icao={self.icao}&zoom=10&largeMode=2&hideButtons&hideSidebar&mapDim=0&overlays={self.get_adsbx_map_overlays()}"
|
||||
get_adsbx_screenshot(self.map_file_name, url_params)
|
||||
url_params = f"largeMode=2&hideButtons&hideSidebar&mapDim=0&zoom=10&icao={self.icao}&overlays={self.get_adsbx_map_overlays()}"
|
||||
get_adsbx_screenshot(self.map_file_name, url_params, overrides=self.overrides)
|
||||
if nearest_airport_dict['distance_mi'] < 3:
|
||||
if "touchngo" in self.circle_history.keys():
|
||||
message = f"Doing touch and goes at {nearest_airport_dict['icao']}"
|
||||
|
@ -759,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()}"
|
||||
wording_context = "Inside" if 'context' not in in_tfr.keys() else "Above" if in_tfr['context'] == 'above' else "Below"
|
||||
message += f" {wording_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)
|
||||
|
||||
|
@ -842,7 +860,7 @@ class Plane:
|
|||
else:
|
||||
url_params += f"&icao={self.icao.lower()}&noIsolation"
|
||||
print(url_params)
|
||||
get_adsbx_screenshot(self.map_file_name, url_params, True, True)
|
||||
get_adsbx_screenshot(self.map_file_name, url_params, True, True, overrides=self.overrides)
|
||||
|
||||
if self.config.getboolean('DISCORD', 'ENABLE'):
|
||||
from defDiscord import sendDis
|
||||
|
@ -858,4 +876,4 @@ class Plane:
|
|||
print(time_since_ra)
|
||||
if time_since_ra.seconds >= 600:
|
||||
print(ra_type)
|
||||
self.recent_ra_types.pop(ra_type)
|
||||
self.recent_ra_types.pop(ra_type)
|
Loading…
Reference in New Issue