Skip to content

OurAirports โ€‹

Nameourairports
CoverageGlobal โ€” airport metadata, not aircraft (different domain from every other data runner)
Data sourcehttps://davidmegginson.github.io/ourairports-data/airports.csv (+ companion regions.csv/countries.csv for name resolution, see below)
FormatCSV (fixed URL)
Run frequencyWeekly (Monday, 05:10 UTC)
Depends on Mictronics for ICAO hexN/A โ€” this runner writes airport:{icao_code} records, not aircraft enrichment, and has no relationship to the Mictronics-provided icao_hex lookup used by the country aircraft-register runners.

How it works โ€‹

The OurAirports CSV is downloaded whole from a fixed URL (no index page or scraping involved) and parsed with csv.DictReader. Rows are filtered to those whose ident is exactly 4 characters (a valid ICAO airport code โ€” 3-character IATA-only idents and other lengths are dropped) and staged into a fresh local SQLite database (the file is deleted and recreated on every run) before being bulk-written to Redis in batches of 10,000. Each staged row also gets a computed phonic field โ€” a voice-friendly spoken name โ€” via compute_phonic(), which supports a host-provided JSON override file for exact per-airport overrides (see below).

Two small companion CSVs โ€” regions.csv and countries.csv, same host โ€” are also downloaded on every run and turned into {code: name} maps (build_code_name_map()). airports.csv's iso_region/iso_country are raw ISO codes with no name column of their own (e.g. AU-QLD, AU); these maps resolve them to display names (Queensland, Australia) at stage time. A code with no matching entry in either map (some iso_region values are unassigned placeholders, e.g. US-U-A) falls back to the raw code rather than going blank.

Columns โ€‹

Source columnImportedNotes
identโœ…Filtered to 4-character ICAO codes; non-4-char rows dropped; used as icao_code and the Redis key
iata_codeโœ…โ†’ iata_code; omitted from the record if blank
nameโœ…โ†’ name; also used as input to phonic computation
municipalityโœ…โ†’ city; also used as input to phonic computation
iso_regionโœ…โ†’ region (resolved to a name via regions.csv, falling back to the raw code if unmatched) and โ†’ region_code (the raw code, always)
iso_countryโœ…โ†’ country (resolved to a name via countries.csv, falling back to the raw code if unmatched) and โ†’ country_code (the raw code, always)
latitude_degโœ…โ†’ latitude (float)
longitude_degโœ…โ†’ longitude (float)
idโŒPresent in source; not read by this runner
typeโŒPresent in source; not read by this runner
elevation_ftโŒPresent in source; not read by this runner
continentโŒPresent in source; not read by this runner
scheduled_serviceโŒPresent in source; not read by this runner
icao_codeโŒPresent in source; not read by this runner โ€” the runner instead derives its own icao_code from the (4-character-filtered) ident column, not from this field
gps_codeโŒPresent in source; not read by this runner
local_codeโŒPresent in source; not read by this runner
home_linkโŒPresent in source; not read by this runner
wikipedia_linkโŒPresent in source; not read by this runner
keywordsโŒPresent in source; not read by this runner

See specs/data-dictionary.yaml (ourairports entry) for full column semantics and cross-source schema notes.

Example Output โ€‹

This runner writes airport:{icao_code} records, not aircraft data, so merge_aircraft.lua does not apply here. Read a record directly with JSON.GET:

bash
docker run --rm --network host redis:latest redis-cli JSON.GET airport:KATL | python3 -m json.tool --sort-keys --no-ensure-ascii
json
{
    "icao_code": "KATL",
    "name": "Hartsfield-Jackson Atlanta International Airport",
    "city": "Atlanta",
    "region": "Georgia",
    "region_code": "US-GA",
    "country": "United States",
    "country_code": "US",
    "phonic": "Atlanta Hartsfield-Jackson"
}

TTL: 14 days (ENRICHMENT_TTL_SECONDS in shared/timing.py), not operator-configurable.

Configuration โ€‹

See Data Runners for the full list of environment variables every runner reads. This runner writes airport:{icao_code} with a fixed 14-day TTL (ENRICHMENT_TTL_SECONDS in shared/timing.py).

MQTT โ€‹

Published once, at the end of a run, to SkyFollower/runner/ourairports/statistic/{name} (all retained):

Topic suffixValueFormat
records_importede.g. 271Integer as string
last_run_ate.g. 2026-07-07T14:32:01.123456+00:00ISO 8601 UTC
last_run_statusSuccess or FailureString

Home Assistant autodiscovery configs are also published (retained) to homeassistant/sensor/SkyFollower_runner_ourairports_{name}/config for each of the three stats above.

Phonic Names โ€‹

Each airport record includes a phonic field โ€” a voice-friendly spoken name used by downstream systems for overhead announcements. "International" and "Airport" are stripped from every computed phonic.

Override file โ€‹

Copy config/runners/phonic_overrides.json.example to config/runners/phonic_overrides.json (relative to docker-compose.core.yaml) and edit it. That directory is mounted onto /app/config; the path defaults to /app/config/phonic_overrides.json and can be overridden with the OVERRIDES_PATH environment variable. Mounting the directory (rather than the file directly) means the override file can be added, edited, or removed without needing to recreate the container.

Format:

json
{
    "KXXX": "Spoken name exactly as desired",
    "KYYY": "Another override"
}

If an airport's ICAO code has an entry in this file, that value is used verbatim โ€” no stripping or any other processing is applied. The general algorithm only runs for airports not in the file.

The file is read once each time the runner starts. Changes take effect on the next run. A missing file is silently ignored.

General algorithm (no override) โ€‹

  1. If name starts with "Greater" or contains " of ": use name as-is.
  2. If city is not present in the airport name: prepend city.
  3. If phonic ends with city: move city to the front.
  4. Strip trailing / or - artifacts (common in names like "City/Town Airport").
  5. Normalise / and - to spaces; collapse extra spaces.
  6. Strip "International" and "Airport" from the result.