Faste download-URLs til officielle dronezone-geodata og naturområder. Designet til automatisk integration — data opdateres dagligt kl. 03:00 CET.
API'et giver adgang til to separate datasæt med hver sin kilde og sit opdateringsforløb. De to datasæt er uafhængige og kan downloades enkeltvis.
| Datasæt | Zonekategorier | Geometrityper | Antal filer |
|---|---|---|---|
| ● ● ● Dronezoner | Rød (flyvesikring), Orange (opmærksomhed), Blå (sikring) | Point + Polygon | 9 |
| ● Naturområder | Grøn (beskyttede naturområder, aktiv/inaktiv) | Polygon | 5 |
| TOTAL | 14 | ||
Datasættet indeholder geografiske dronezoner inddelt i tre kategorier (rød, orange, blå) med hver to lagtyper — en signatur (Point) og et område (Polygon). Alle lag er inkluderet i samtlige downloadformater. Udgåede zoner filtreres automatisk fra ved den daglige opdatering.
| Lag | Geometri | Antal features |
|---|---|---|
| TOTAL | — | |
Følgende datatyper indgår ikke i dette datasæt og skal hentes hos de respektive dataejere:
NOTAM'er og ICAO-kort — hentes hos Naviair (naviair.dk), som er dataejer for luftfartsinformation.
Veje og jernbaner — hentes hos Kortforsyningen / Styrelsen for Dataforsyning og Infrastruktur (dataforsyningen.dk).
Alle dronezoner i ét GeoJSON-dokument. Velegnet til web-applikationer, Leaflet, Mapbox, OpenLayers og lignende kortbiblioteker.
import requests, json
URL = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data"
response = requests.get(URL)
response.raise_for_status()
drone_zones = response.json()
print(f"Hentet {len(drone_zones['features'])} dronezoner")
with open("dronezoner.geojson", "w", encoding="utf-8") as f:
json.dump(drone_zones, f, ensure_ascii=False, indent=2)const res = await fetch(
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data"
);
const data = await res.json();
console.log(`Hentet ${data.features.length} dronezoner`);
// Leaflet eksempel
L.geoJSON(data).addTo(map);# Download til fil curl -o dronezoner.geojson \ "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data" # Pretty-print curl -s "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data" | jq .
using var client = new HttpClient();
var url = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data";
var json = await client.GetStringAsync(url);
await File.WriteAllTextAsync("dronezoner.geojson", json);Alle punkt-signaturer (lufthavne, heliporte, opmærksomhedspunkter m.fl.) i KML-format. Velegnet til Google Earth, Google Maps og andre KML-kompatible klienter.
import requests
URL = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/19b7580f09d04433b4ce6d2884feeb33/data"
response = requests.get(URL)
response.raise_for_status()
with open("dronezoner_point.kml", "wb") as f:
f.write(response.content)
print("KML Point downloaded")curl -o dronezoner_point.kml \ "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/19b7580f09d04433b4ce6d2884feeb33/data"
Alle polygon-zoner (restriktionszoner, opmærksomhedsområder, sikringskritiske områder) i KML-format.
Komprimeret udgave af KML Point. Mindre filstørrelse, ideel til distribution og Google Earth.
Komprimeret KML med røde polygon-zoner — flyvesikringskritiske områder. Separate farvefiler giver bedre kompatibilitet med Google Earth og enklere integration.
Komprimeret KML med orange polygon-zoner — opmærksomhedsområder.
Komprimeret KML med blå polygon-zoner — sikringskritiske områder.
OGC-standard SQLite-baseret format. Understøtter vektor- og rasterdata. Ideel til QGIS og moderne GIS-software.
import requests
import geopandas as gpd
URL = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/048f825f32e3444d8989a6701f477eec/data"
response = requests.get(URL)
response.raise_for_status()
with open("dronezoner.gpkg", "wb") as f:
f.write(response.content)
gdf = gpd.read_file("dronezoner.gpkg")
print(f"Indlæst {len(gdf)} dronezoner, CRS: {gdf.crs}")curl -o dronezoner.gpkg \ "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/048f825f32e3444d8989a6701f477eec/data" # Vis info med GDAL ogrinfo dronezoner.gpkg
ESRI Shapefile i ZIP-format (.shp, .shx, .dbf m.fl.). Industristandard — kompatibel med alle GIS-systemer.
import requests, zipfile
from io import BytesIO
import geopandas as gpd
URL = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/6eaf92665c0244c7b5b2f56f805d8717/data"
response = requests.get(URL)
response.raise_for_status()
with open("dronezoner_shp.zip", "wb") as f:
f.write(response.content)
with zipfile.ZipFile(BytesIO(response.content)) as z:
z.extractall("dronezoner_shp")
print(f"Udpakket: {z.namelist()}")curl -o dronezoner_shapefile.zip \ "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/6eaf92665c0244c7b5b2f56f805d8717/data" unzip dronezoner_shapefile.zip -d dronezoner_shp/
Datasættet viser beskyttede naturområder med droneflyvningsrestriktioner. Datasættet indeholder polygon-geometrier med både aktive og sæsonmæssigt inaktive zoner. KML/KMZ-filerne inkluderer visuel aktiv/inaktiv-styling.
| Lag | Geometri | Aktive | Inaktive | Total |
|---|---|---|---|---|
| TOTAL | — | — | — | |
Alle naturområder i ét GeoJSON-dokument. Indeholder både aktive og inaktive zoner med attributter for status og sæsonperiode.
import requests, json
URL = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/ff657943724944faaf19807380f5e24a/data"
response = requests.get(URL)
response.raise_for_status()
nature_zones = response.json()
print(f"Hentet {len(nature_zones['features'])} naturområder")
# Filtrer aktive/inaktive
active = [f for f in nature_zones['features']
if f['properties'].get('Status') == 'Aktiv']
print(f"Heraf {len(active)} aktive zoner")
with open("naturomraader.geojson", "w", encoding="utf-8") as f:
json.dump(nature_zones, f, ensure_ascii=False, indent=2)const res = await fetch(
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/ff657943724944faaf19807380f5e24a/data"
);
const data = await res.json();
console.log(`Hentet ${data.features.length} naturområder`);
// Leaflet eksempel med farve efter status
L.geoJSON(data, {
style: f => ({
color: f.properties.Status === 'Aktiv' ? '#27ae60' : '#95a5a6',
fillOpacity: f.properties.Status === 'Aktiv' ? 0.3 : 0.1
})
}).addTo(map);# Download til fil curl -o naturomraader.geojson \ "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/ff657943724944faaf19807380f5e24a/data" # Tæl features curl -s "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/ff657943724944faaf19807380f5e24a/data" \ | jq '.features | length'
using var client = new HttpClient();
var url = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/ff657943724944faaf19807380f5e24a/data";
var json = await client.GetStringAsync(url);
await File.WriteAllTextAsync("naturomraader.geojson", json);Alle naturområder i KML-format med visuel aktiv/inaktiv-styling. Aktive zoner vises med udfyldt grøn farve, inaktive med gennemsigtig grå.
Komprimeret KML med alle naturområder. Aktiv/inaktiv-styling bevaret. Mindre filstørrelse, ideel til Google Earth.
Naturområder i OGC GeoPackage-format. Ideel til QGIS og moderne GIS-software.
import requests
import geopandas as gpd
URL = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/3b8fb69058af464c9bcef2ca3e11b875/data"
response = requests.get(URL)
response.raise_for_status()
with open("naturomraader.gpkg", "wb") as f:
f.write(response.content)
gdf = gpd.read_file("naturomraader.gpkg")
print(f"Indlæst {len(gdf)} naturområder, CRS: {gdf.crs}")curl -o naturomraader.gpkg \ "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/3b8fb69058af464c9bcef2ca3e11b875/data" ogrinfo naturomraader.gpkg
Naturområder i ESRI Shapefile-format (ZIP). Kompatibel med alle GIS-systemer.
Anbefalet til produktionssystemer.
Scriptet henter metadata fra ArcGIS Online og bruger feltet modified (epoch millisekunder)
til at afgøre om data er opdateret i dag (dansk tid, CET/CEST).
Bemærk: Feltet modified er det eneste pålidelige tidsstempel til maskinelt tjek.
Andre felter som description og snippet indeholder også opdateringsdato i klartekst, men er beregnet til menneskeligt aflæsning — brug altid modified til automatisering.
Hvis data ikke er fra i dag, returneres en fejl — enten fordi jeres job kører før kl. 03:00 CET, eller fordi det planlagte opdateringsscript ikke har kørt.
På den måde undgår I at bruge forældet data uden at vide det.
| Exit code | Betydning | Handling |
|---|---|---|
0 | Data er fra i dag | Filen downloades og gemmes |
1 | Data er IKKE fra i dag | Ingen download — WARNING/ERROR logges |
2 | Metadata-kald fejlede | Ingen download — netværksfejl |
| Situation | Resultat | Exit code |
|---|---|---|
| Data er opdateret i dag | ✓ Download og brug data | 0 |
| Jeres job kører før kl. 03:00 | ⚠ Data er fra i går — endnu ikke opdateret | 1 |
| Opdateringsscriptet fejlede | ✗ Data er forældet (X dage) — undersøg | 1 |
| Metadata-kald fejler | ✗ Netværksfejl — retry eller alarm | 2 |
"""
Dronezone data-freshness guard
Tjekker om data er opdateret I DAG ved at læse feltet 'modified'
fra ArcGIS Online item-metadata (?f=json).
'modified' er et epoch-timestamp i millisekunder (fx 1771552890000)
og angiver hvornår filen sidst blev opdateret på serveren.
Det er det eneste felt der skal bruges til maskinelt freshness-tjek.
(Felterne 'description' og 'snippet' indeholder samme dato i klartekst,
men er til menneskeligt aflæsning — brug IKKE dem til automatisering.)
Exit codes (standard for CI/CD og scheduled tasks):
0 = Data er fra i dag — alt OK, fil downloadet
1 = Data er IKKE fra i dag — forældet (WARNING eller ERROR)
2 = Metadata-kald fejlede — netværksfejl, retry eller alarm
"""
import sys
import logging
import requests
from datetime import datetime, timezone, timedelta
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s"
)
log = logging.getLogger("dronezone")
META_URL = (
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/"
"content/items/980697acd04d4a9bb1fd34bbefab924a?f=json"
)
DATA_URL = (
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/"
"content/items/980697acd04d4a9bb1fd34bbefab924a/data"
)
CET = timezone(timedelta(hours=1)) # Vinter: CET (UTC+1)
# CET = timezone(timedelta(hours=2)) # Sommer: CEST (UTC+2)
OUTPUT_FILE = "dronezoner.geojson"
# ↑ VIGTIGT: Erstat med stien hvor JERES system gemmer filen, fx:
# Windows: r"C:\Dronekortdata\dataFraDronezoner\dronezoner.geojson"
# Linux: "/opt/dronedata/dronezoner.geojson"
# macOS: "/Users/dit-navn/dronedata/dronezoner.geojson"
def check_and_download():
# 1. Hent metadata
try:
resp = requests.get(META_URL, timeout=30)
resp.raise_for_status()
meta = resp.json()
except requests.RequestException as e:
log.error(f"Kunne ikke hente metadata: {e}")
sys.exit(2) # Netværksfejl
# 2. Parse modified timestamp
modified_ms = meta.get("modified")
if not modified_ms:
log.error("Feltet 'modified' mangler i metadata")
sys.exit(2)
modified_dt = datetime.fromtimestamp(modified_ms / 1000, tz=CET)
today = datetime.now(tz=CET).date()
log.info(f"Senest opdateret: {modified_dt.strftime('%d/%m %Y kl. %H:%M')} CET")
# 3. Tjek om data er fra i dag
if modified_dt.date() != today:
days_old = (today - modified_dt.date()).days
if days_old == 1:
log.warning(
"DATA IKKE OPDATERET I DAG. "
"Seneste data er fra i går. "
"Sandsynlig årsag: Jeres job kører før kl. 03:00, "
"eller det daglige opdateringsscript har endnu ikke kørt."
)
else:
log.error(
f"DATA ER FORÆLDET — {days_old} dage gammelt! "
f"Seneste opdatering: {modified_dt.strftime('%d/%m %Y')}. "
"Det planlagte opdateringsscript kan være fejlet. "
"Kontakt Trafikstyrelsen hvis problemet fortsætter."
)
sys.exit(1) # Data er IKKE frisk
# 4. Data er fra i dag — download
log.info("✓ Data er opdateret i dag — downloader...")
try:
data_resp = requests.get(DATA_URL, timeout=60)
data_resp.raise_for_status()
except requests.RequestException as e:
log.error(f"Download fejlede: {e}")
sys.exit(2)
with open(OUTPUT_FILE, "wb") as f:
f.write(data_resp.content)
log.info(f"✓ Gemt {OUTPUT_FILE} ({len(data_resp.content):,} bytes)")
sys.exit(0) # Alt OK
if __name__ == "__main__":
check_and_download()/**
* Dronezone data-freshness guard (Node.js / Deno / Bun)
*
* Læser feltet 'modified' (epoch ms) fra ArcGIS Online metadata.
* Det er det eneste felt der skal bruges til maskinelt freshness-tjek.
* ('description' og 'snippet' indeholder dato i klartekst, men er til
* menneskeligt aflæsning — brug dem IKKE til automatisering.)
*
* Exit codes: 0 = data fra i dag (OK), 1 = forældet, 2 = netværksfejl
*/
const META_URL =
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a?f=json";
const DATA_URL =
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data";
async function checkAndDownload() {
// 1. Hent metadata
let meta;
try {
const res = await fetch(META_URL);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
meta = await res.json();
} catch (e) {
console.error(`[ERROR] Kunne ikke hente metadata: ${e.message}`);
process.exit(2);
}
// 2. Tjek modified-dato i dansk tid (CET = UTC+1)
const modifiedMs = meta.modified;
const modified = new Date(modifiedMs);
// Konverter til CET-dato (tilføj 1 time for UTC+1)
const cetOffset = 1; // Skift til 2 for sommertid
const modCET = new Date(modifiedMs + cetOffset * 3600000);
const nowCET = new Date(Date.now() + cetOffset * 3600000);
const modDate = modCET.toISOString().slice(0, 10);
const todayDate = nowCET.toISOString().slice(0, 10);
console.log(`[INFO] Senest opdateret: ${modified.toISOString()} (CET: ${modDate})`);
// 3. Valider freshness
if (modDate !== todayDate) {
const daysOld = Math.floor((nowCET - modCET) / 86400000);
if (daysOld <= 1) {
console.warn(
`[WARNING] Data er fra i går. ` +
`Opdateringsscriptet har sandsynligvis endnu ikke kørt (kl. 03:00 CET).`
);
} else {
console.error(
`[ERROR] Data er ${daysOld} dage gammelt! ` +
`Det planlagte opdateringsscript kan være fejlet.`
);
}
process.exit(1);
}
// 4. Data er frisk — download
console.log("[INFO] ✓ Data er fra i dag — downloader...");
const data = await fetch(DATA_URL);
const fs = await import("fs/promises");
const buffer = Buffer.from(await data.arrayBuffer());
await fs.writeFile("dronezoner.geojson", buffer);
console.log(`[INFO] ✓ Gemt dronezoner.geojson (${buffer.length.toLocaleString()} bytes)`);
process.exit(0);
}
checkAndDownload();#!/usr/bin/env bash
# dronezone_freshness_guard.sh
#
# Læser feltet 'modified' (epoch ms) fra ArcGIS Online metadata.
# Det er det eneste felt der skal bruges til maskinelt freshness-tjek.
# ('description'/'snippet' indeholder klartekst-dato, men kun til mennesker.)
#
# Exit codes: 0 = data fra i dag (OK), 1 = forældet, 2 = netværksfejl
set -euo pipefail
META_URL="https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a?f=json"
DATA_URL="https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data"
# Hent modified timestamp (epoch ms)
MODIFIED_MS=$(curl -sf "$META_URL" | jq -r '.modified')
if [ -z "$MODIFIED_MS" ] || [ "$MODIFIED_MS" = "null" ]; then
echo "[ERROR] Kunne ikke hente metadata" >&2
exit 2
fi
# Konverter til sekunder og sammenlign med i dag (CET)
MODIFIED_SEC=$((MODIFIED_MS / 1000))
MODIFIED_DATE=$(TZ="Europe/Copenhagen" date -d "@$MODIFIED_SEC" +%Y-%m-%d)
TODAY=$(TZ="Europe/Copenhagen" date +%Y-%m-%d)
echo "[INFO] Senest opdateret: $(TZ='Europe/Copenhagen' date -d "@$MODIFIED_SEC" '+%d/%m %Y kl. %H:%M') CET"
if [ "$MODIFIED_DATE" != "$TODAY" ]; then
DAYS_OLD=$(( ( $(date -d "$TODAY" +%s) - $(date -d "$MODIFIED_DATE" +%s) ) / 86400 ))
if [ "$DAYS_OLD" -le 1 ]; then
echo "[WARNING] Data er fra i går. Script kører muligvis før kl. 03:00." >&2
else
echo "[ERROR] Data er ${DAYS_OLD} dage gammelt! Opdateringsscript kan være fejlet." >&2
fi
exit 1
fi
echo "[INFO] ✓ Data er fra i dag — downloader..."
curl -sf -o dronezoner.geojson "$DATA_URL"
echo "[INFO] ✓ Gemt dronezoner.geojson"
exit 0// DronezoneFreshnessGuard.cs
//
// Læser feltet 'modified' (epoch ms) fra ArcGIS Online metadata.
// Det er det eneste felt der skal bruges til maskinelt freshness-tjek.
// ('description'/'snippet' indeholder klartekst-dato, men kun til mennesker.)
//
// Exit codes: 0 = data fra i dag (OK), 1 = forældet, 2 = netværksfejl
using System.Text.Json;
var metaUrl = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a?f=json";
var dataUrl = "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a/data";
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
// 1. Hent metadata
JsonDocument meta;
try {
var json = await client.GetStringAsync(metaUrl);
meta = JsonDocument.Parse(json);
} catch (Exception ex) {
Console.Error.WriteLine($"[ERROR] Metadata-kald fejlede: {ex.Message}");
Environment.Exit(2);
return;
}
// 2. Parse modified
var modifiedMs = meta.RootElement.GetProperty("modified").GetInt64();
var modifiedUtc = DateTimeOffset.FromUnixTimeMilliseconds(modifiedMs);
var cet = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
var modifiedCet = TimeZoneInfo.ConvertTime(modifiedUtc, cet);
var todayCet = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, cet);
Console.WriteLine($"[INFO] Senest opdateret: {modifiedCet:dd/MM yyyy 'kl.' HH:mm} CET");
// 3. Tjek freshness
if (modifiedCet.Date != todayCet.Date) {
var daysOld = (todayCet.Date - modifiedCet.Date).Days;
if (daysOld <= 1)
Console.Error.WriteLine("[WARNING] Data er fra i går. Script kører muligvis før kl. 03:00.");
else
Console.Error.WriteLine($"[ERROR] Data er {daysOld} dage gammelt!");
Environment.Exit(1);
return;
}
// 4. Download
Console.WriteLine("[INFO] ✓ Data er fra i dag — downloader...");
var data = await client.GetByteArrayAsync(dataUrl);
await File.WriteAllBytesAsync("dronezoner.geojson", data);
Console.WriteLine($"[INFO] ✓ Gemt dronezoner.geojson ({data.Length:N0} bytes)");
Environment.Exit(0);Sammenligner serverens modified-tidsstempel med din lokale fils ændringstid. Downloader kun hvis serveren har nyere data. OBS: Dette mønster fortæller ikke om data faktisk er fra i dag — brug Mønster 1 hvis det er vigtigt.
import os
import requests
from datetime import datetime, timezone
META_URL = (
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/"
"content/items/980697acd04d4a9bb1fd34bbefab924a?f=json"
)
DATA_URL = (
"https://trafikstyrelsen.maps.arcgis.com/sharing/rest/"
"content/items/980697acd04d4a9bb1fd34bbefab924a/data"
)
LOCAL_FILE = "dronezoner.geojson"
# ↑ VIGTIGT: Erstat med stien til JERES lokale fil, fx:
# Windows: r"C:\Dronekortdata\dataFraDronezoner\dronezoner.geojson"
# Linux: "/opt/dronedata/dronezoner.geojson"
# macOS: "/Users/dit-navn/dronedata/dronezoner.geojson"
meta = requests.get(META_URL).json()
modified_dt = datetime.fromtimestamp(meta["modified"] / 1000, tz=timezone.utc)
print(f"Server-data opdateret: {modified_dt.isoformat()}")
if os.path.exists(LOCAL_FILE):
local_mtime = datetime.fromtimestamp(
os.path.getmtime(LOCAL_FILE), tz=timezone.utc
)
if modified_dt > local_mtime:
print("→ Ny data tilgængelig — downloader...")
r = requests.get(DATA_URL)
with open(LOCAL_FILE, "wb") as f:
f.write(r.content)
else:
print("→ Lokal kopi er allerede opdateret.")
else:
print("→ Ingen lokal kopi fundet — downloader...")
r = requests.get(DATA_URL)
with open(LOCAL_FILE, "wb") as f:
f.write(r.content)# Hent modified-tidspunkt
curl -s "https://trafikstyrelsen.maps.arcgis.com/sharing/rest/content/items/980697acd04d4a9bb1fd34bbefab924a?f=json" \
| jq '{modified: .modified, title: .title}'