
Aviation Weather
- 9 installs
- 33 repo stars
- Updated April 26, 2026
- bighardperson/computer-science-skills-collection
aviation-weather is a skill that fetches METAR, TAF, and PIREP aviation weather data from the FAA aviationweather.gov API.
About
This skill fetches real-time aviation weather (METAR, TAF, PIREPs) from the FAA's aviationweather.gov API via a bundled Python script. It classifies conditions into flight categories and supports specific airports, lat/lon PIREP searches, and raw JSON output. A developer or pilot uses it for flight planning and airport weather briefings.
- Fetches METAR, TAF, and PIREP aviation weather from the FAA aviationweather.gov API
- Color-codes flight categories (VFR/MVFR/IFR/LIFR) by ceiling and visibility
- Supports airport codes, lat/lon PIREP search, history hours, and JSON output
Aviation Weather by the numbers
- 9 all-time installs (skills.sh)
- Ranked #1,497 of 2,719 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Jul 30, 2026 (Skillselion catalog sync)
aviation-weather capabilities & compatibility
Free; queries the public FAA aviationweather.gov API via a bundled Python script, no API key.
- Works with
- weather
- Use cases
- research
- Runs
- Runs locally
- Pricing
- Free
What aviation-weather says it does
Fetch aviation weather data (METAR, TAF, PIREPs) from aviationweather.gov. Use for flight planning, weather briefings, checking airport conditions, or any pilot-related weather queries.
Fetch real-time aviation weather from the FAA's aviationweather.gov API.
PIREPs near a location (lat/lon)
npx skills add https://github.com/bighardperson/computer-science-skills-collection --skill aviation-weatherAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 9 |
|---|---|
| repo stars | ★ 33 |
| Last updated | April 26, 2026 |
| Repository | bighardperson/computer-science-skills-collection ↗ |
What it does
Fetch real-time METAR, TAF, and PIREP aviation weather from aviationweather.gov for flight planning.
Who is it for?
Pilots and flight-planning workflows needing METAR/TAF/PIREP data and flight-category summaries.
Skip if: General non-aviation weather; it is scoped to aviationweather.gov data and ICAO airport codes.
When should I use this skill?
the user asks about METAR, TAF, PIREP, flight weather, airport conditions, or ICAO codes.
By the numbers
- Four flight categories (VFR, MVFR, IFR, LIFR)
- Default airports KSMO, KLAX, KVNY
Files
Aviation Weather
Fetch real-time aviation weather from the FAA's aviationweather.gov API.
Quick Reference
# METAR for specific airports
python3 scripts/wx.py KSMO KLAX KVNY
# METAR + TAF
python3 scripts/wx.py KSMO KLAX --metar --taf
# Just TAF
python3 scripts/wx.py KSMO --taf
# PIREPs near a location (lat/lon)
python3 scripts/wx.py --pirep --lat 34.0 --lon -118.4 --radius 100
# Raw output with JSON
python3 scripts/wx.py KSMO --json
# Verbose (show raw METAR text)
python3 scripts/wx.py KSMO -vDefault Airports
When no stations specified, defaults to Santa Monica area: KSMO, KLAX, KVNY
Flight Categories
- 🟢 VFR - Ceiling >3000ft AGL and visibility >5sm
- 🔵 MVFR - Ceiling 1000-3000ft or visibility 3-5sm
- 🔴 IFR - Ceiling 500-1000ft or visibility 1-3sm
- 🟣 LIFR - Ceiling <500ft or visibility <1sm
Common SoCal Airports
| Code | Name |
|---|---|
| KSMO | Santa Monica |
| KLAX | Los Angeles Intl |
| KVNY | Van Nuys |
| KBUR | Burbank |
| KTOA | Torrance |
| KSNA | John Wayne |
| KFUL | Fullerton |
| KCMA | Camarillo |
| KOXR | Oxnard |
| KPSP | Palm Springs |
Options
--metar,-m: Fetch METAR (default)--taf,-t: Fetch TAF forecast--pirep,-p: Fetch pilot reports--hours N: Hours of METAR history (default: 2)--lat,--lon: Location for PIREP search--radius N: PIREP search radius in nm (default: 100)--verbose,-v: Show raw observation text--json: Output raw JSON data
{
"ownerId": "kn79d0jjeyfmc9vsdtrecfgamh7zz3w5",
"slug": "aviation-weather",
"version": "1.0.0",
"publishedAt": 1769448056750
}{
"slug": "aviation-weather",
"name": "Aviation Weather",
"version": "1.0.0",
"installedAt": 1776152380491,
"source": "skillhub"
}#!/usr/bin/env python3
"""Aviation weather fetcher - METAR, TAF, and PIREPs from aviationweather.gov"""
import argparse
import json
import sys
from urllib.request import urlopen
from urllib.error import URLError
from datetime import datetime
BASE_URL = "https://aviationweather.gov/api/data"
def fetch_metar(stations: list[str], hours: int = 2) -> list[dict]:
"""Fetch METAR data for given stations."""
ids = ",".join(s.upper() for s in stations)
url = f"{BASE_URL}/metar?ids={ids}&format=json&hours={hours}"
try:
with urlopen(url, timeout=10) as resp:
return json.loads(resp.read())
except URLError as e:
print(f"Error fetching METAR: {e}", file=sys.stderr)
return []
def fetch_taf(stations: list[str]) -> list[dict]:
"""Fetch TAF data for given stations."""
ids = ",".join(s.upper() for s in stations)
url = f"{BASE_URL}/taf?ids={ids}&format=json"
try:
with urlopen(url, timeout=10) as resp:
return json.loads(resp.read())
except URLError as e:
print(f"Error fetching TAF: {e}", file=sys.stderr)
return []
def fetch_pireps(lat: float, lon: float, radius: int = 100) -> list[dict]:
"""Fetch PIREPs within a bounding box around lat/lon."""
# Create bounding box roughly matching the radius (1 degree ~ 60nm)
delta = radius / 60
bbox = f"{lon-delta},{lat-delta},{lon+delta},{lat+delta}"
url = f"{BASE_URL}/pirep?format=json&bbox={bbox}"
try:
with urlopen(url, timeout=10) as resp:
content = resp.read()
if not content:
return []
return json.loads(content)
except URLError as e:
print(f"Error fetching PIREPs: {e}", file=sys.stderr)
return []
def decode_flight_category(cat: str) -> str:
"""Return emoji + description for flight category."""
categories = {
"VFR": "🟢 VFR",
"MVFR": "🔵 MVFR",
"IFR": "🔴 IFR",
"LIFR": "🟣 LIFR"
}
return categories.get(cat, cat)
def format_metar(data: list[dict], verbose: bool = False) -> str:
"""Format METAR data for display."""
if not data:
return "No METAR data available."
lines = []
for m in data:
station = m.get("icaoId", "????")
raw = m.get("rawOb", "")
cat = decode_flight_category(m.get("fltCat", ""))
# Basic info
temp = m.get("temp")
dewp = m.get("dewp")
wdir = m.get("wdir")
wspd = m.get("wspd")
vis = m.get("visib")
alt = m.get("altim")
header = f"**{station}** {cat}"
details = []
if temp is not None and dewp is not None:
details.append(f"Temp: {temp}°C / Dewpoint: {dewp}°C")
if wdir is not None and wspd is not None:
wdir_str = "VRB" if wdir == "VRB" else f"{wdir:03d}°"
details.append(f"Wind: {wdir_str} @ {wspd}kt")
if vis is not None:
details.append(f"Vis: {vis}sm")
if alt is not None:
details.append(f"Altimeter: {alt:.2f}")
lines.append(header)
if verbose:
lines.append(f" {raw}")
lines.append(" " + " | ".join(details))
lines.append("")
return "\n".join(lines)
def format_taf(data: list[dict], verbose: bool = False) -> str:
"""Format TAF data for display."""
if not data:
return "No TAF data available."
lines = []
for t in data:
station = t.get("icaoId", "????")
raw = t.get("rawTAF", "")
lines.append(f"**{station} TAF**")
if verbose:
lines.append(f" {raw}")
else:
# Just show raw TAF, it's most useful
lines.append(f" {raw}")
lines.append("")
return "\n".join(lines)
def format_pireps(data: list[dict]) -> str:
"""Format PIREP data for display."""
if not data:
return "No PIREPs in the area."
lines = ["**Pilot Reports:**"]
for p in data:
raw = p.get("rawOb", "")
lines.append(f" • {raw}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Fetch aviation weather data")
parser.add_argument("stations", nargs="*", help="ICAO station IDs (e.g., KLAX KSMO)")
parser.add_argument("--metar", "-m", action="store_true", help="Fetch METAR (default if no flags)")
parser.add_argument("--taf", "-t", action="store_true", help="Fetch TAF")
parser.add_argument("--pirep", "-p", action="store_true", help="Fetch PIREPs (requires --lat/--lon)")
parser.add_argument("--lat", type=float, help="Latitude for PIREP search")
parser.add_argument("--lon", type=float, help="Longitude for PIREP search")
parser.add_argument("--radius", type=int, default=100, help="PIREP search radius in nm (default: 100)")
parser.add_argument("--hours", type=int, default=2, help="Hours of METAR history (default: 2)")
parser.add_argument("--verbose", "-v", action="store_true", help="Show raw observations")
parser.add_argument("--json", action="store_true", help="Output raw JSON")
args = parser.parse_args()
# Default to METAR if no flags
if not args.metar and not args.taf and not args.pirep:
args.metar = True
# Default stations for Santa Monica area
if not args.stations and (args.metar or args.taf):
args.stations = ["KSMO", "KLAX", "KVNY"]
print("Using default stations: KSMO, KLAX, KVNY\n")
output = []
if args.metar and args.stations:
data = fetch_metar(args.stations, args.hours)
if args.json:
print(json.dumps(data, indent=2))
else:
output.append(format_metar(data, args.verbose))
if args.taf and args.stations:
data = fetch_taf(args.stations)
if args.json:
print(json.dumps(data, indent=2))
else:
output.append(format_taf(data, args.verbose))
if args.pirep:
lat = args.lat or 34.0158 # Default: Santa Monica
lon = args.lon or -118.4513
data = fetch_pireps(lat, lon, args.radius)
if args.json:
print(json.dumps(data, indent=2))
else:
output.append(format_pireps(data))
if not args.json:
print("\n".join(output))
if __name__ == "__main__":
main()