-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
128 lines (109 loc) · 3.79 KB
/
main.py
File metadata and controls
128 lines (109 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import csv
from math import asin, cos, radians, sin, sqrt
import requests
from fastapi import FastAPI
from geopy.geocoders import Nominatim
app = FastAPI()
# -----------------------------
# Load airports from OurAirports
# -----------------------------
def load_airports():
airports = []
with open("airports.csv", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
try:
if (
row["icao_code"]
and row["latitude_deg"]
and row["longitude_deg"]
and row["type"] in ["large_airport", "medium_airport"]
and row["scheduled_service"] == "yes"
):
airports.append(
{
"icao": row["icao_code"],
"name": row["name"],
"lat": float(row["latitude_deg"]),
"lon": float(row["longitude_deg"]),
}
)
except:
continue
print(f"Loaded {len(airports)} airports")
return airports
airports = load_airports()
# -----------------------------
# Geocoder
# -----------------------------
geolocator = Nominatim(user_agent="metar_weather_api")
# -----------------------------
# Haversine distance
# -----------------------------
def get_distance(lat1, lon1, lat2, lon2):
dlon = radians(lon2 - lon1)
dlat = radians(lat2 - lat1)
a = (
sin(dlat / 2) ** 2
+ cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2) ** 2
)
return 6371 * 2 * asin(sqrt(a))
# -----------------------------
# Find nearest airports
# -----------------------------
def find_nearest_airports(lat, lon, limit=5):
distances = []
for airport in airports:
dist = get_distance(lat, lon, airport["lat"], airport["lon"])
distances.append((dist, airport))
distances.sort(key=lambda x: x[0])
return distances[:limit]
# -----------------------------
# Fetch METAR from Aviation Weather Center
# -----------------------------
def fetch_metar(icao):
url = f"https://aviationweather.gov/api/data/metar?ids={icao}&format=json"
try:
res = requests.get(url, timeout=5)
if res.status_code != 200:
return None
data = res.json()
if not data:
return None
return data[0] # structured METAR
except:
return None
# -----------------------------
# API Endpoint
# -----------------------------
@app.get("/weather")
def get_weather(address: str):
# 1. Geocode
location = geolocator.geocode(address)
if not location:
return {"error": "Address not found"}
lat, lon = location.latitude, location.longitude
# 2. Find nearest airports
nearby_airports = find_nearest_airports(lat, lon)
# 3. Try each airport until we find METAR
for dist, airport in nearby_airports:
print(f"Trying airport: {airport['icao']}")
metar = fetch_metar(airport["icao"])
if metar:
return {
"input_address": address,
"coordinates": {"lat": lat, "lon": lon},
"airport": airport["icao"],
"airport_name": airport["name"],
"distance_km": round(dist, 2),
"weather": {
"temperature_c": metar.get("temp"),
"dew_point_c": metar.get("dewp"),
"wind_direction_deg": metar.get("wdir"),
"wind_speed_kt": metar.get("wspd"),
"visibility_km": metar.get("visib"),
"pressure_hpa": metar.get("altim"),
},
"metar_raw": metar.get("rawOb"),
}
return {"error": "No METAR data found nearby"}