# Задержки FAA

Интеграция задержек FAA в национальной системе воздушного пространства (NAS) — запреты вылетов, программы GDP и оповещения о закрытии аэропортов.



Готовые к запуску примеры запросов программ задержки вылетов на земле (GDP), запретов вылетов (ground stop), закрытий и программ регулирования потоков в воздушном пространстве (AFP) FAA. Определения полей приведены в справочнике [Задержки FAA](/docs/v31/faa-delays). Данные охватывают только аэропорты США (программы FAA ATCSCC).

| # | Вопрос                                                          | Используемые данные      |
| - | --------------------------------------------------------------- | ------------------------ |
| 1 | Есть ли сейчас активные задержки FAA где-либо в США?            | `GET /delays/faa`        |
| 2 | Действует ли сейчас в KJFK программа задержки вылетов на земле? | `GET /delays/faa/{icao}` |
| 3 | Проверить хабовые аэропорты на наличие активных программ        | `GET /delays/faa/{icao}` |

<DocRequirements>
  <DocRequirementAuth />
</DocRequirements>

### Установка [#install]

Приведённые ниже скрипты используют `requests` для вызовов API и `rich` для вывода в терминал. Установите один раз:

```bash
pip install requests rich
```

***

### 1. Сводка задержек FAA по всей стране [#1-nationwide-faa-delay-snapshot]

**Вопрос:** Есть ли сейчас активные [задержки FAA](https://www.faa.gov/about/office_org/headquarters_offices/ato/service_units/operations/at_delay_info) где-либо в США?

Один вызов `/delays/faa` возвращает все текущие программы задержки вылетов на земле, запреты вылетов, закрытия и программы регулирования потоков в воздушном пространстве. Кэшируйте ответ не дольше 2 минут.

```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()
```

**Результат:** Если ограничений нет, выводится «No active [FAA delays](https://www.faa.gov/about/office_org/headquarters_offices/ato/service_units/operations/at_delay_info)». В противном случае выводится сводная панель, а за ней — таблицы с цветовой кодировкой для каждого типа оповещений: жёлтым — GDP, красным — запреты вылетов, пурпурным — закрытия.

***

### 2. Статус задержек в KJFK [#2-kjfk-delay-status]

**Вопрос:** Действует ли сейчас в KJFK программа задержки вылетов на земле?

Используйте эндпоинт для конкретного аэропорта, чтобы проверить один аэропорт, не загружая полную картину по всей стране.

```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()
```

**Результат:** Если ограничений нет — зелёная панель «No active delays». В противном случае — по панели с цветовой кодировкой на каждый тип оповещения (жёлтая — GDP, красная — запрет вылетов, пурпурная — закрытие) со сроками и причиной.

***

### 3. Панель задержек по хабовым аэропортам [#3-hub-airport-delay-dashboard]

**Вопрос:** В каких из моих хабовых аэропортов сейчас действуют программы FAA?

Запросите каждый хаб по отдельности и сведите результаты в одну таблицу-панель. Обновляйте данные не чаще одного раза в 2 минуты.

```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()
```

**Результат:** Единая таблица-панель с одной строкой на каждый хаб. Аэропорты с активными программами выделены красным, аэропорты без ограничений — зелёным. В каждой строке указаны тип оповещения, средняя задержка и фрагмент причины.
