Skip to content

maetthu-indermuehle/metar_display

Repository files navigation

METAR Dashboard

A self-hosted aviation weather learning tool for PPL students. Displays live METARs and TAFs for a configured set of airports, with a full-screen situational awareness map powered by live OpenAIP and aviationweather.gov data.

Built to run on a wall-mounted iPad, served from a Raspberry Pi on the local network.

Features

METAR tab

  • Live data from aviationweather.gov — free, no API key
  • Raw report alongside decoded fields: wind, visibility, temperature, altimeter (inHg + hPa), clouds, present weather
  • Runway Visual Range (RVR) decoded when present
  • Cloud type remark decoding (CU1TCU1AC3AC3 → Cumulus 1/8, Towering Cumulus 1/8, …)
  • Tap any cloud type tag for a photo and aviation description
  • Flight rules badge per airport: VFR / MVFR / IFR / LIFR in standard aviation colours
  • Observation time in Zulu and local time for the airport's timezone

TAF tab

  • Decoded into individual forecast periods with full DD/HH:MMZ time ranges
  • Each period shows its raw source string alongside decoded fields
  • Supports all period types: Base, FM, BECMG, TEMPO, INTER, PROB 30%/40%
  • Wind shear (WS groups) decoded and highlighted
  • Temperature forecast (TX/TN groups) when present (European airports)

Map tab

  • Airport dots coloured live by METAR flight category (VFR/MVFR/IFR/LIFR) for aerodromes, airports, and international airports; airports without a current METAR stay gray
  • VOR/VORDME/VORTAC/DVOR rendered as an 8-pointed compass rose; NDB as concentric dashed circles
  • OpenAIP airspace polygons: Class B/C/D, Class E surface, Restricted, Prohibited, Danger, MOA/Military — loaded per viewport, cached 1 hour
  • Click any airspace polygon (or stack of polygons) for a popup: name, altitude range, and TWR frequency for controlled airspace
  • Full airport popup: type, elevation, frequencies (TWR/GND/ATIS/APP/UNICOM), runways (designator, length, surface)
  • Airport search: enter any ICAO code to fetch its live METAR + TAF
  • Live ADS-B aircraft positions from airplanes.live — type-specific icons coloured by altitude, optional callsign/registration filter, click to show flight path trail
  • Data layers auto-refresh on map pan/zoom; METAR colours refresh every time new data is loaded

Settings

  • All settings are persisted in localStorage — survive page reloads and container redeployments without any server-side account
  • Airport List: override the server-configured airport list per device
  • Map Default View: save the current map centre and zoom as your personal default
  • Base map: Dark Matter (default), Positron, Voyager, OpenStreetMap
  • Overlay: FAA VFR Sectional (US only) or Openflightmaps ICAO charts (Europe)
  • Layer toggles: show/hide each aviation layer independently
  • Airspace opacity: slider to adjust fill opacity
  • Airport type filter: 9 types; heliports, military, and ultralight strips hidden by default
  • Live Aircraft: toggle on/off; optional callsign/registration whitelist (one per line)

General

  • 5-minute auto-refresh with live Zulu/local clock in the header
  • Dark theme, touch-friendly, responsive layout
  • Canadian (CY__) and Swiss (LS__) airports out of the box

Architecture

browser / iPad
      │
      ▼
 nginx (frontend)        ← serves static HTML/CSS/JS
      │ /api/*
      ▼
 FastAPI (backend)       ← fetches, parses and caches weather + map data
      │
      ├── aviationweather.gov  ← METAR/TAF (free, no key)
      ├── OpenAIP Core API     ← airspaces, airports, navaids (API key required)
      └── airplanes.live       ← live ADS-B positions (free, no key)

Two Docker containers orchestrated with Docker Compose:

Container Stack Role
backend Python 3.12, FastAPI, avwx-engine, httpx Weather + map data API
frontend nginx Serves static files, proxies /api/* to backend

Configuration

Environment variables

Variable Default Description
OPENAIP_API_KEY (required for map) OpenAIP API key — free account
AIRPORTS See below Comma-separated ICAO codes for the server-default METAR/TAF list
CACHE_TTL_SECONDS 300 METAR/TAF cache TTL in seconds
MAP_CENTER_ICAO (first airport) ICAO code to centre the map on
MAP_CENTER_LAT / MAP_CENTER_LON (derived) Override map centre coordinates directly
MAP_ZOOM 8 Initial map zoom level
AIRCRAFT_REFRESH_SECONDS 10 How often the browser polls for new ADS-B positions (also sets the server-side cache TTL)

Set these in your docker-compose.yml under backend → environment, or in a .env file referenced via env_file.

The airport list and map view can also be overridden per device from the browser's Settings dialog without touching the server.

Default airports

ICAO Airport
CYXX Abbotsford, BC
CYVR Vancouver, BC
CYYJ Victoria, BC
CYLW Kelowna, BC
CYYQ Campbell River, BC
CYHE Hope / Agassiz, BC
LSZB Bern, Switzerland
LSZH Zurich, Switzerland
LSGG Geneva, Switzerland

Override with AIRPORTS=CYXX,CYVR,LSZH in your environment, or edit the list in the browser via Settings → Airport List.

API Endpoints

Endpoint Description
GET /api/metar/all METARs for all configured stations; accepts optional ?airports=CYXX,CYVR
GET /api/metar/{icao} METAR for a single station
GET /api/metar/map?bounds=W,S,E,N Flight categories for all stations in bbox (5-min cache)
GET /api/taf/all TAFs for all configured stations; accepts optional ?airports=CYXX,CYVR
GET /api/taf/{icao} TAF for a single station
GET /api/map/features?bounds=W,S,E,N OpenAIP airspaces, airports, navaids for bbox (1-hour cache)
GET /api/map-config Map centre and zoom from environment
GET /api/aircraft?bounds=W,S,E,N Live ADS-B positions as GeoJSON (cached per AIRCRAFT_REFRESH_SECONDS)
GET /api/aircraft/config Returns {"refresh_seconds": N} for the frontend timer
GET /health Health check
GET /docs Interactive API docs (FastAPI built-in)

Deployment (Raspberry Pi / OMV)

The Pi deployment uses pre-built multi-platform images (amd64 + arm64) from GitHub Container Registry, with Watchtower for automatic updates. After any push to main, GitHub Actions builds new images and Watchtower picks them up within 5 minutes — no SSH needed.

docker-compose.yml on the Pi

services:
  backend:
    image: ghcr.io/YOUR_USERNAME/metar-display-backend:latest
    restart: unless-stopped
    expose:
      - "8000"
    environment:
      - OPENAIP_API_KEY=your_key_here
      - AIRPORTS=CYXX,CYVR,LSZH   # optional
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

  frontend:
    image: ghcr.io/YOUR_USERNAME/metar-display-frontend:latest
    restart: unless-stopped
    ports:
      - "8080:80"
    depends_on:
      - backend
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

  watchtower:
    image: containrrr/watchtower:latest
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_POLL_INTERVAL=300
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_LABEL_ENABLE=true

iPad Setup

Add to Home Screen

  1. Open Safari and navigate to the dashboard URL
  2. Tap ShareAdd to Home Screen
  3. Name it METAR and tap Add

The app opens full-screen with no browser chrome.

Keep the screen always on

Guided Access (recommended for wall-mounted displays):

  1. Settings → Accessibility → Guided Access → enable
  2. Open the METAR app
  3. Triple-click Home/Side button → Start

The screen stays on and locked to the app. Triple-click again + passcode to exit.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors