Skip to content

🇳🇱 nl-ilt

CountryNetherlands
Registration prefixPH-
Data sourcehttps://www.ilent.nl/documenten/lijsten/luchtvaart/databestanden/luchtvaartregister-data
FormatODS spreadsheet (date-stamped filename, changes monthly, discovered via index page)
Run frequencyWeekly (Thursday, 05:10 UTC)
Depends on Mictronics for ICAO hexNo — the ILT register publishes the ICAO hex directly in its X-Ponder column, so records can be written to aircraft:registry:{icao_hex} without a RediSearch reverse lookup, and without mictronics having run first.

How it works

The ILT index page is scraped with a regex for a URL (absolute or relative) containing the known filename stem luchtvaartuigregister-ilt-datas2...*.ods; the file is downloaded to a temp path and parsed with odfpy. Row 0 holds annotated headers (bracket suffixes like [details=n][kolom=j] are stripped off), row 1 is an informational text row that is skipped, and row 2 onward is data. Cells that carry OpenDocument's numbercolumnsrepeated attribute are expanded so that merged/repeated blank cells don't shift later columns out of alignment (with a guard against implausibly large repeat counts on trailing empty cells, which are collapsed back to one). A row is only written if X-Ponder is a valid 6-hex ICAO code and Registration is non-empty. 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.

Whenever a record has an aircraft.type_designator, aircraft:type:{type_designator} is looked up in Redis (populated by the mictronics runner) and, if found, its manufacturer_model and wake_turbulence_category are each set directly on this record (independently — a type entry with only one of the two still sets that one) — unconditionally, regardless of whether Mictronics also has values for the same hex. This runner's own type_designator is sourced directly from the ILT register and is authoritative; merge_aircraft.lua's "registry wins over mictronics" precedence rule guarantees these values take priority at read time either way. The lookup is not a hard dependency — a missing reference table entry, or the table not existing yet, leaves the record exactly as it would have been without this step.

Columns

Source columnImportedNotes
FlagPresent in source; not read by this runner
Registration→ top-level registration
RegisteredPresent in source; not read by this runner
LatestOwnerChangePresent in source; not read by this runner
PrevCountryPresent in source; not read by this runner
PrevMarkPresent in source; not read by this runner
Manufactureraircraft.manufacturer
ManufacturedInPresent in source; not read by this runner
Modelaircraft.model
Serialaircraft.serial_number
X-PonderValidated as a 6-hex ICAO code; used directly as icao_hex (no Mictronics lookup needed)
Builtaircraft.manufactured_date (YYYY-01-01T00:00:00Z), only if a 4-digit year
Groupaircraft.type, mapped through a fixed table (e.g. Small aeroplaneAirplane, RotorcraftHelicopter); unmapped values pass through unchanged
ConfigurationPresent in source; not read by this runner
MTOMPresent in source; not read by this runner
MLMPresent in source; not read by this runner
ICAO-codeaircraft.type_designator; also used to look up aircraft:type:{type_designator} in Redis, setting aircraft.manufacturer_model and aircraft.wake_turbulence_category when found
AOCPresent in source; not read by this runner
83BisPresent in source; not read by this runner
RepresentativePresent in source; not read by this runner
MortgagePresent in source; not read by this runner
VolumePresent in source; not read by this runner
LegalBasePresent in source; not read by this runner
Enginesaircraft.powerplant.count, only if numeric
EngKindaircraft.powerplant.type, mapped through a fixed table; "Engine - not defined" is dropped rather than stored
EngManufactureraircraft.powerplant.manufacturer; the literal value "Unknown" is filtered out
EngModelaircraft.powerplant.model; values containing "not further defined" are filtered out
PropsPresent in source; not read by this runner
PropKindPresent in source; not read by this runner
PropManufacturerPresent in source; not read by this runner
PropModelPresent in source; not read by this runner
NoiseRequirementsPresent in source; not read by this runner
NoiseCatPresent in source; not read by this runner
NoiseRcrdPresent in source; not read by this runner
LevelAppPresent in source; not read by this runner
LevelFoPresent in source; not read by this runner
LevelOfPresent in source; not read by this runner
LevelSlPresent in source; not read by this runner
LevelToPresent in source; not read by this runner
RegistrIssuedPresent in source; not read by this runner
RegistrExpiryPresent in source; not read by this runner
CofA (Form24/25)_Iss.Present in source; not read by this runner
AirwIssuedPresent in source; not read by this runner
AirwExpiryPresent in source; not read by this runner
AirwKindPresent in source; not read by this runner
AirwValPresent in source; not read by this runner
NoiseIssuedPresent in source; not read by this runner
NoiseExpiryPresent in source; not read by this runner
RegBlockPresent in source; not read by this runner
Site2TitlePresent in source; not read by this runner
Site2Descr1Present in source; not read by this runner
Site2Descr2Present in source; not read by this runner
Site2Tech1Present in source; not read by this runner
Site2Tech2Present in source; not read by this runner
Site2Tech3Present in source; not read by this runner
Site2Tech4Present in source; not read by this runner
Site2Tech5Present in source; not read by this runner
Site2Noise1Present in source; not read by this runner
Site2Noise2Present in source; not read by this runner
Site2Doc1Present in source; not read by this runner
Site2Doc2Present in source; not read by this runner
Site2Doc3Present in source; not read by this runner

See specs/data-dictionary.yaml (nl-ilt 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 484674 | python3 -m json.tool --sort-keys --no-ensure-ascii
json
{
    "aircraft": {
        "manufactured_date": "2007-01-01T00:00:00Z",
        "manufacturer": "Piper Aircraft, Inc.",
        "manufacturer_model": "PIPER PA-28-140/150/160/180",
        "model": "PA-28-181",
        "powerplant": {
            "count": 1,
            "manufacturer": "AVCO Corporation, Lycoming Division",
            "model": "O-360-A4M",
            "type": "Piston"
        },
        "serial_number": "2843664",
        "type": "Airplane",
        "type_designator": "P28A",
        "wake_turbulence_category": "Light"
    },
    "icao_hex": "484674",
    "military": false,
    "registration": "PH-WKB",
    "source": "nl-ilt"
}
bash
docker run --rm --network host redis:latest redis-cli EVAL "$(cat ./shared/lua/merge_aircraft.lua)" 0 484F73 | python3 -m json.tool --sort-keys --no-ensure-ascii
json
{
    "aircraft": {
        "manufactured_date": "2012-01-01T00:00:00Z",
        "manufacturer": "Airbus S.A.S. (Société par Actions Simplifiée)",
        "manufacturer_model": "AIRBUS A-330-300",
        "model": "A330-303",
        "powerplant": {
            "count": 2,
            "manufacturer": "General Electric Company, Aircraft Engine Group",
            "model": "CF6-80E1A3",
            "type": "Turbo-fan"
        },
        "serial_number": "1300",
        "type": "Airplane",
        "type_designator": "A333",
        "wake_turbulence_category": "Heavy"
    },
    "icao_hex": "484F73",
    "military": false,
    "registration": "PH-AKD",
    "source": "nl-ilt"
}

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/nl-ilt/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_nl_ilt_{name}/config for each of the three stats above.