Skip to content

🇺🇸 us-faa

CountryUnited States
Registration prefixN (no dash; N-number, e.g. N62770)
Data sourcehttps://registry.faa.gov/database/ReleasableAircraft.zip
FormatZIP of pipe-free CSV files (fixed URL; no discovery step)
Run frequencyWeekly (Saturday, 05:10 UTC)
Depends on Mictronics for ICAO hexNo — master.txt (the registration file) publishes the Mode S code hex directly.

How it works

The FAA Releasable Aircraft Database ZIP is downloaded from a fixed URL and extracted entirely in memory; filenames are lowercased, and a .txt.txt double-extension bug the FAA has occasionally shipped is normalized away. Three files are staged into a local SQLite database rather than written straight to Redis, so that per-tail registrations can be joined against reference tables cheaply:

  • engine.txt — engine make/model/type/power reference, keyed by engine code
  • acftref.txt — aircraft make/model/seats/category reference, keyed by aircraft code
  • master.txt — one row per registered tail, keyed by icao_hex (only rows with a well-formed 6-character Mode S hex are kept)

This runner supports the 2017+ column layout only. Numeric FAA type codes (engine type, aircraft type, aircraft class, registrant type) are decoded via lookup tables into human-readable strings. Powerplant power is reported as thrust for jet/fan/ramjet engine types and as horsepower for piston/turboprop/turboshaft/2-4-cycle/rotary types. The final Redis write is driven by a single LEFT JOIN query across the staged tables and flushed to Redis in batches of 10,000. Every written record explicitly sets military: false — this register is exclusively civil, and the explicit value ensures a stale military: true flag (from Mictronics or a prior record on a reused hex) is corrected on re-registration.

Columns

The FAA ZIP contains eight files (ardata.pdf, ACFTREF.txt, ENGINE.txt, DEALER.txt, DOCINDEX.txt, MASTER.txt, RESERVED.txt, DEREG.txt); this runner reads only acftref.txt, engine.txt, and master.txt, joined via the codes below. Column names below are verbatim from each file's real header row.

engine.txt

Source columnImportedNotes
CODEJoin key to master.txt's engine-code column
MFRaircraft.powerplant.manufacturer
MODELaircraft.powerplant.model
TYPEaircraft.powerplant.type (decoded)
HORSEPOWERaircraft.powerplant.power_value (piston/turboprop/turboshaft/2-4-cycle/rotary types)
THRUSTaircraft.powerplant.power_value (turbo-jet/turbo-fan/ramjet types)

acftref.txt

Source columnImportedNotes
CODEJoin key to master.txt's aircraft-code column
MFRaircraft.manufacturer
MODELaircraft.model
TYPE-ACFTaircraft.type (decoded)
TYPE-ENGaircraft.powerplant.type (decoded; used if no matching engine.txt row)
AC-CATaircraft.category (decoded)
BUILD-CERT-INDPresent in source; not read by this runner
NO-ENGaircraft.powerplant.count
NO-SEATSaircraft.seats
AC-WEIGHTPresent in source; not read by this runner
SPEEDPresent in source; not read by this runner
TC-DATA-SHEETPresent in source; not read by this runner
TC-DATA-HOLDERPresent in source; not read by this runner

master.txt

Source columnImportedNotes
N-NUMBERregistration (prefixed with N)
SERIAL NUMBERaircraft.serial_number
MFR MDL CODEJoin key to acftref.txt
ENG MFR MDLJoin key to engine.txt
YEAR MFRaircraft.manufactured_date
TYPE REGISTRANTregistrant.type (decoded)
NAMEregistrant.names[0]
STREETregistrant.street
STREET2registrant.street
CITYregistrant.city
STATEregistrant.administrative_area
ZIP CODEregistrant.postal_code
REGIONPresent in source; not read by this runner
COUNTYPresent in source; not read by this runner
COUNTRYregistrant.country (defaults to US)
LAST ACTION DATEPresent in source; not read by this runner
CERT ISSUE DATEPresent in source; not read by this runner
CERTIFICATIONPresent in source; not read by this runner
TYPE AIRCRAFTPresent in source; not read by this runner
TYPE ENGINEPresent in source; not read by this runner
STATUS CODEPresent in source; not read by this runner
MODE S CODEPresent in source; not read by this runner (distinct from MODE S CODE HEX, below, which is used)
FRACT OWNERPresent in source; not read by this runner
AIR WORTH DATEPresent in source; not read by this runner
OTHER NAMES(1-5)registrant.names[1:]
EXPIRATION DATEPresent in source; not read by this runner
UNIQUE IDPresent in source; not read by this runner
KIT MFRPresent in source; not read by this runner
KIT MODELPresent in source; not read by this runner
MODE S CODE HEXicao_hex; rows without a well-formed 6-character hex are discarded

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

Example Output

Read back the merged record for a given ICAO hex (combines this runner's data with Mictronics and any other sources that have written to the same key):

bash
docker run --rm --network host redis:latest redis-cli EVAL "$(cat ./shared/lua/merge_aircraft.lua)" 0 A833A4 | python3 -m json.tool --sort-keys --no-ensure-ascii
json
{
    "aircraft": {
        "category": "Land",
        "manufactured_date": "2008-01-01T00:00:00Z",
        "manufacturer": "CESSNA",
        "manufacturer_model": "CESSNA 172 Skyhawk",
        "model": "172S",
        "powerplant": {
            "count": 1,
            "manufacturer": "LYCOMING",
            "model": "IO-360-L2A",
            "power_type": "Horsepower",
            "power_value": 180,
            "type": "Piston"
        },
        "seats": 4,
        "serial_number": "172S10747",
        "type": "Airplane",
        "type_designator": "C172",
        "wake_turbulence_category": "Light"
    },
    "icao_hex": "A833A4",
    "military": false,
    "registrant": {
        "administrative_area": "FL",
        "city": "WINTER PARK",
        "country": "US",
        "names": [
            "HOG ISLAND FLYING LLC"
        ],
        "postal_code": "327893726",
        "street": [
            "807 W MORSE BLVD STE 101"
        ],
        "type": "LLC"
    },
    "registration": "N62770",
    "source": "us-faa"
}
bash
docker run --rm --network host redis:latest redis-cli EVAL "$(cat ./shared/lua/merge_aircraft.lua)" 0 A8AE7F | python3 -m json.tool --sort-keys --no-ensure-ascii
json
{
    "aircraft": {
        "category": "Land",
        "manufactured_date": "1990-01-01T00:00:00Z",
        "manufacturer": "BOEING",
        "manufacturer_model": "BOEING 757-200",
        "model": "757-232",
        "powerplant": {
            "count": 2,
            "manufacturer": null,
            "model": null,
            "power_type": null,
            "power_value": null,
            "type": "Turbo-fan"
        },
        "seats": 178,
        "serial_number": "24421",
        "type": "Airplane",
        "type_designator": "B752",
        "wake_turbulence_category": "Medium"
    },
    "icao_hex": "A8AE7F",
    "military": false,
    "registrant": {
        "administrative_area": "GA",
        "city": "ATLANTA",
        "country": "US",
        "names": [
            "DELTA AIR LINES INC"
        ],
        "postal_code": "303543743",
        "street": [
            "1775 M H JACKSON SERVICE RD",
            "DEPT 595 AIRCRAFT REGISTRATIONS"
        ],
        "type": "Corporation"
    },
    "registration": "N659DL",
    "source": "us-faa"
}

Configuration

Reads settings.json (mounted at /app/settings.json):

ParameterRequiredDefaultNotes
redis.hostRedis connection host
redis.port6379
mqtt.hostOmit the whole mqtt block to skip completion-stats publishing entirely
mqtt.port1883
mqtt.usernameOptional MQTT auth; omit for an anonymous broker
mqtt.password
redis_ttl_days14TTL applied to each aircraft:registry:{icao_hex} key written by this runner

MQTT

Published once, at the end of a run, to SkyFollower/runner/us-faa/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_us_faa_{name}/config for each of the three stats above.