Skip to content

Switzerland ๐Ÿ‡จ๐Ÿ‡ญ BAZL Registry โ€‹

Namech-bazl-registry
CountrySwitzerland
Registration prefixHB-
Data sourcehttps://app02.bazl.admin.ch/web/bazl-backend/lfr/csv
FormatJSON API (POST, fixed endpoint) returning a UTF-16 BE, semicolon-delimited CSV body (~3,100 records)
Run frequencyWeekly (Wednesday, 13:10 UTC)
Depends on Mictronics for ICAO hexNo โ€” the FOCA/BAZL register publishes the Mode S hex address directly (Aircraft Address HEX column).

How it works โ€‹

A single POST request to the fixed FOCA/BAZL backend endpoint (page_result_limit: 10000, current_page_number: 1, filtered to aircraftStatus: ["Registered"]) returns the entire register as one UTF-16 encoded, semicolon-delimited CSV โ€” no authentication or page discovery needed. Rows are additionally filtered to Status == "Registered" and to those with a valid 6-hex-digit Aircraft Address HEX. Note that the CSV column headers all carry a leading space (e.g. " Registration", " Aircraft Type") โ€” this is preserved verbatim in the source and must be matched exactly when reading row.get(...). The Main Owner field is a single unstructured address string (Name[, Canton]?, Street, PostalCode City, Switzerland) that is best-effort parsed by popping known trailing/canton tokens off a comma-split list, since there's no per-field structure to rely on. 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 description_code (ICAO Doc 8643 description code, e.g. L2J) are set directly on this record โ€” unconditionally, regardless of whether Mictronics also has values for the same hex. This runner's own type_designator is sourced directly from FOCA/BAZL 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
LfrIDโŒPresent in source; not read by this runner
Registrationโœ…HB-prefix โ†’ registration
StatusโŒUsed to filter to Registered rows only; value itself is not stored
Date of RegistrationโŒPresent in source; not read by this runner
Date of DeregistrationโŒPresent in source; not read by this runner
Manufacturerโœ…โ†’ aircraft.manufacturer
Aicraft Model (sic, source typo)โœ…โ†’ aircraft.model
ICAO Aircraft Typeโœ…โ†’ aircraft.type_designator; also used to look up aircraft:type:{type_designator} in Redis, setting aircraft.manufacturer_model and aircraft.description_code when found
Marketing DesignationโŒPresent in source; not read by this runner
Aircraft Typeโœ…Decoded via a type map (e.g. Homebuilt Airplane โ†’ Airplane) โ†’ aircraft.type
Certification BasisโŒPresent in source; not read by this runner
Airworthiness CategoryโŒPresent in source; not read by this runner
Legal BasisโŒPresent in source; not read by this runner
TCDSโŒPresent in source; not read by this runner
ELAโŒPresent in source; not read by this runner
Aircraft Address DECโŒPresent in source; not read by this runner
Aircraft Address HEXโœ…โ†’ icao_hex
Aircraft Address OCTโŒPresent in source; not read by this runner
Aircraft Address BINโŒPresent in source; not read by this runner
ELT CodeโŒPresent in source; not read by this runner
Year of Manufactureโœ…4-digit year โ†’ aircraft.manufactured_date (YYYY-01-01)
Serial Numberโœ…โ†’ aircraft.serial_number
BRSโŒPresent in source; not read by this runner
MOPSCโœ…Summed with Minimum Crew โ†’ aircraft.seats
Minimum Crewโœ…Summed with MOPSC โ†’ aircraft.seats
MTOMโŒPresent in source; not read by this runner
Engine manufacturerโœ…โ†’ aircraft.powerplant.manufacturer
Engineโœ…First comma-separated value โ†’ aircraft.powerplant.model
Engine Categoryโœ…First comma-separated value decoded via engine map โ†’ aircraft.powerplant.type
Propeller manufacturerโŒPresent in source; not read by this runner
PropellerโŒPresent in source; not read by this runner
Noise StandardโŒPresent in source; not read by this runner
Noise LevelโŒPresent in source; not read by this runner
Noise ClassโŒPresent in source; not read by this runner
Main Ownerโœ…Best-effort parsed into registrant.names/street/city/postal_code; registrant.country is hardcoded CH
Main OperatorโŒPresent in source; not read by this runner
Part OwnersโŒPresent in source; not read by this runner
Part OperatorsโŒPresent in source; not read by this runner
Billing AddressโŒPresent in source; not read by this runner

See specs/data-dictionary.yaml (ch-bazl-registry 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 4B012D | python3 -m json.tool --sort-keys --no-ensure-ascii
json
{
    "aircraft": {
        "description_code": "L1P",
        "manufactured_date": "1944-01-01",
        "manufacturer": "PIPER AIRCRAFT CORPORATION",
        "manufacturer_model": "PIPER J-3 Cub",
        "model": "J3C-65/L-4.",
        "powerplant": {
            "manufacturer": "ROLLS-ROYCE MOTORS LTD.",
            "model": "RR O-200-A",
            "type": "Piston"
        },
        "seats": 2,
        "serial_number": "12026",
        "type": "Airplane",
        "type_designator": "J3"
    },
    "data_sources": [
        "mictronics",
        "ch-bazl-registry"
    ],
    "icao_hex": "4B012D",
    "military": false,
    "registrant": {
        "city": "Wilihof",
        "country": "CH",
        "names": [
            "Kaufmann, Patrick"
        ],
        "postal_code": "6236",
        "street": [
            "Dorfstrasse 22"
        ]
    },
    "registration": "HB-ALP"
}
bash
docker run --rm --network host redis:latest redis-cli EVAL "$(cat ./shared/lua/merge_aircraft.lua)" 0 4B0280 | python3 -m json.tool --sort-keys --no-ensure-ascii
json
{
    "aircraft": {
        "description_code": "L2J",
        "manufactured_date": "2021-01-01",
        "manufacturer": "AIRBUS S.A.S.",
        "manufacturer_model": "AIRBUS A-320neo",
        "model": "A320-251N",
        "powerplant": {
            "manufacturer": "SAFRAN AIRCRAFT ENGINES",
            "model": "LEAP-1A26",
            "type": "Turbo-jet"
        },
        "seats": 197,
        "serial_number": "10186",
        "type": "Airplane",
        "type_designator": "A20N"
    },
    "data_sources": [
        "mictronics",
        "ch-bazl-registry",
        "airportwebcams-special-liveries"
    ],
    "icao_hex": "4B0280",
    "military": false,
    "registrant": {
        "country": "CH",
        "names": [
            "easyJet Airline Company Limited, London Luton Airport LU2 9PF Luton"
        ],
        "street": [
            "Bedfordshire"
        ]
    },
    "registration": "HB-AYQ",
    "special_livery": "NEO"
}

Configuration โ€‹

See Data Runners for the full list of environment variables every runner reads. This runner writes aircraft:registry:{icao_hex} 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/ch-bazl-registry/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_ch_bazl_registry_{name}/config for each of the three stats above.