# FAA-Verspätungen

FAA-NAS-Verspätungen integrieren — Ground Stops, GDP-Programme und Warnungen zu Flughafenschließungen.



Lauffähige Beispiele zur Abfrage von FAA-Ground-Delay-Programmen, Ground Stops, Schließungen und Airspace Flow Programs. Felddefinitionen finden Sie in der Referenz [FAA-Verspätungen](/docs/v31/faa-delays). Die Daten decken ausschließlich US-Flughäfen ab (Programme des FAA ATCSCC).

| # | Frage                                              | Verwendete Daten         |
| - | -------------------------------------------------- | ------------------------ |
| 1 | Gibt es gerade aktive FAA-Verspätungen in den USA? | `GET /delays/faa`        |
| 2 | Gilt für KJFK derzeit ein Ground Delay Program?    | `GET /delays/faa/{icao}` |
| 3 | Drehkreuz-Flughäfen auf aktive Programme prüfen    | `GET /delays/faa/{icao}` |

<DocRequirements>
  <DocRequirementAuth />
</DocRequirements>

### Installation [#install]

Die folgenden Skripte verwenden `requests` für API-Aufrufe und `rich` für die Terminalausgabe. Einmalig installieren:

```bash
pip install requests rich
```

***

### 1. Landesweite Momentaufnahme der FAA-Verspätungen [#1-nationwide-faa-delay-snapshot]

**Frage:** Gibt es gerade aktive [FAA-Verspätungen](https://www.faa.gov/about/office_org/headquarters_offices/ato/service_units/operations/at_delay_info) in den USA?

Ein einziger Aufruf von `/delays/faa` liefert alle aktuellen Ground Delay Programs, Ground Stops, Schließungen und Airspace Flow Programs. Speichern Sie die Daten höchstens 2 Minuten im Cache.

```python
import os

import requests
from rich.console import Console
from rich.panel import Panel
from rich.table import Table

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"


def fetch_faa_delays() -> dict | None:
    r = requests.get(f"{BASE}/delays/faa", headers=HEADERS, timeout=(10, 15))
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def main() -> None:
    data = fetch_faa_delays()
    if not data:
        console.print("[red]Could not retrieve FAA delay data.[/red]")
        return

    total = data.get("total_alerts", 0)
    if total == 0:
        console.print("[green]No active FAA delays.[/green]")
        return

    console.print(Panel(f"[bold]{total}[/bold] active FAA alert(s)", style="yellow"))

    ground_delays = data.get("ground_delays", [])
    if ground_delays:
        t = Table(title="Ground Delay Programs (GDP)", show_lines=True)
        t.add_column("Airport", style="yellow")
        t.add_column("Name")
        t.add_column("Avg Delay")
        t.add_column("Max Delay")
        t.add_column("Reason")
        for row in ground_delays:
            t.add_row(
                row.get("airport", "—"),
                row.get("airport_name", "—"),
                row.get("avg_delay", "—"),
                row.get("max_delay", "—"),
                row.get("reason", "—"),
            )
        console.print(t)

    ground_stops = data.get("ground_stops", [])
    if ground_stops:
        t = Table(title="Ground Stops (GS)", show_lines=True)
        t.add_column("Airport", style="red")
        t.add_column("Name")
        t.add_column("End Time")
        t.add_column("Reason")
        for row in ground_stops:
            t.add_row(
                row.get("airport", "—"),
                row.get("airport_name", "—"),
                row.get("end_time", "—"),
                row.get("reason", "—"),
            )
        console.print(t)

    closures = data.get("closures", [])
    if closures:
        t = Table(title="Closures", show_lines=True)
        t.add_column("Airport", style="magenta")
        t.add_column("Name")
        t.add_column("Begin")
        t.add_column("Reopen")
        t.add_column("Reason")
        for row in closures:
            t.add_row(
                row.get("airport", "—"),
                row.get("airport_name", "—"),
                row.get("begin", "—"),
                row.get("reopen", "—"),
                row.get("reason", "—"),
            )
        console.print(t)


if __name__ == "__main__":
    main()
```

**Ausgabe:** Gibt „No active [FAA delays](https://www.faa.gov/about/office_org/headquarters_offices/ato/service_units/operations/at_delay_info)“ aus, wenn keine Einschränkungen bestehen. Andernfalls erscheint ein Übersichts-Panel, gefolgt von farbcodierten Tabellen für jede Art von Warnung — Gelb für GDPs, Rot für Ground Stops, Magenta für Schließungen.

***

### 2. Verspätungsstatus von KJFK [#2-kjfk-delay-status]

**Frage:** Gilt für KJFK derzeit ein Ground Delay Program?

Verwenden Sie den flughafenspezifischen Endpoint, um einen einzelnen Flughafen zu prüfen, ohne das vollständige landesweite Lagebild herunterzuladen.

```python
import os

import requests
from rich.console import Console
from rich.panel import Panel

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"

AIRPORT = "KJFK"


def fetch_airport_delays(icao: str) -> dict | None:
    r = requests.get(
        f"{BASE}/delays/faa/{icao}",
        headers=HEADERS,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def main() -> None:
    data = fetch_airport_delays(AIRPORT)
    if not data:
        console.print(f"[red]No delay data returned for {AIRPORT}.[/red]")
        return

    total = data.get("total_alerts", 0)
    if total == 0:
        console.print(
            Panel(f"[green]No active delays at {AIRPORT}.[/green]", style="green")
        )
        return

    for gd in data.get("ground_delays", []):
        console.print(
            Panel(
                f"[bold yellow]Ground Delay Program (GDP)[/bold yellow]\n"
                f"Avg delay: {gd.get('avg_delay', '—')}  "
                f"Max delay: {gd.get('max_delay', '—')}\n"
                f"Reason: {gd.get('reason', '—')}",
                style="yellow",
                title=AIRPORT,
            )
        )

    for gs in data.get("ground_stops", []):
        console.print(
            Panel(
                f"[bold red]Ground Stop (GS)[/bold red]\n"
                f"End time: {gs.get('end_time', '—')}\n"
                f"Reason: {gs.get('reason', '—')}",
                style="red",
                title=AIRPORT,
            )
        )

    for cl in data.get("closures", []):
        console.print(
            Panel(
                f"[bold magenta]Closure[/bold magenta]\n"
                f"Begin: {cl.get('begin', '—')}  Reopen: {cl.get('reopen', '—')}\n"
                f"Reason: {cl.get('reason', '—')}",
                style="magenta",
                title=AIRPORT,
            )
        )


if __name__ == "__main__":
    main()
```

**Ausgabe:** Ein grünes Panel „No active delays“, wenn keine Einschränkungen bestehen. Andernfalls ein farbcodiertes Panel pro Warnungsart (Gelb für GDP, Rot für Ground Stop, Magenta für Schließung) mit Angaben zu Zeitraum und Grund.

***

### 3. Verspätungs-Dashboard für Drehkreuz-Flughäfen [#3-hub-airport-delay-dashboard]

**Frage:** Für welche meiner Drehkreuz-Flughäfen gelten gerade aktive FAA-Programme?

Rufen Sie jedes Drehkreuz einzeln ab und erstellen Sie daraus eine gemeinsame Dashboard-Tabelle. Aktualisieren Sie höchstens alle 2 Minuten.

```python
import os
import concurrent.futures

import requests
from rich.console import Console
from rich.table import Table

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"

HUB_AIRPORTS = ["KJFK", "KLAX", "KORD", "KATL"]


def fetch_airport_delays(icao: str) -> tuple[str, dict | None]:
    try:
        r = requests.get(
            f"{BASE}/delays/faa/{icao}",
            headers=HEADERS,
            timeout=(10, 15),
        )
        if r.status_code == 404:
            return icao, None
        r.raise_for_status()
        return icao, r.json()
    except Exception as exc:  # noqa: BLE001
        console.print(f"[red]Error fetching {icao}: {exc}[/red]")
        return icao, None


def summarise(data: dict | None) -> tuple[str, str, str, str]:
    """Return (active, alert_type, avg_delay, reason_snippet)."""
    if not data or data.get("total_alerts", 0) == 0:
        return "NO", "—", "—", "—"

    types = []
    avg_delay = "—"
    reason = "—"

    for gd in data.get("ground_delays", []):
        types.append("GDP")
        avg_delay = gd.get("avg_delay", "—")
        reason = (gd.get("reason") or "")[:40]

    for _ in data.get("ground_stops", []):
        types.append("GS")

    for _ in data.get("closures", []):
        types.append("Closure")

    for _ in data.get("airspace_flow_programs", []):
        types.append("AFP")

    return "YES", ", ".join(types) or "—", avg_delay, reason or "—"


def main() -> None:
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
        results = dict(pool.map(fetch_airport_delays, HUB_AIRPORTS))

    table = Table(title="Hub Airport FAA Delay Dashboard", show_lines=True)
    table.add_column("Airport", style="bold", no_wrap=True)
    table.add_column("Active", justify="center")
    table.add_column("Alert Type")
    table.add_column("Avg Delay", justify="center")
    table.add_column("Reason")

    for icao in HUB_AIRPORTS:
        active, alert_type, avg_delay, reason = summarise(results.get(icao))
        color = "red" if active == "YES" else "green"
        table.add_row(
            icao,
            f"[{color}]{active}[/{color}]",
            alert_type,
            avg_delay,
            reason,
        )

    console.print(table)
    console.print("[dim]Cache for 2 minutes max — FAA ATCSCC data, US only.[/dim]")


if __name__ == "__main__":
    main()
```

**Ausgabe:** Eine gemeinsame Dashboard-Tabelle mit einer Zeile pro Drehkreuz. Flughäfen mit aktiven Programmen werden rot angezeigt, Flughäfen ohne Einschränkungen grün. Jede Zeile enthält die Art der Warnung, die durchschnittliche Verspätung und einen Auszug aus dem Grund.
