Am 14.08.17 erreichte mich die Nachricht vom DWD, dass es nun den Open Data Server gibt und dieser bis Ende des Jahres den GDS (FTP-Server) ablösen wird.
Alle Infos zum Open Data Server hier!
Bei näherer Recherche, wie ich denn darüber an die Wetterwarnungen komme, habe ich festgestellt, dass es etwas einfacher wird mit diesem Open Data Server. Die bisherige CAP-Zip-Datei lässt sich über den Server unter immer der gleichen URL abrufen. Hier muss man nun nicht mehr die aktuellste Datei ermitteln:
https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_DWD_STAT/ Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMDWD_COMMUNEUNION_DE.zip
Wenn Ihr Euch jetzt fragt „https?“, kann ich nur sagen „Ja, https!“. Das heißt der ganze FTP-Quatsch fliegt aus dem Script raus und macht es deutlich einfacher. Glücklicherweise lässt sich über die http-header das Änderungsdatum der Zip-Datei ermitteln, damit man auch weiß, ob ein erneuter Download überhaupt nötig ist. Der Server unterstützt zwar auch Directory Listing, aber da das Änderungsdatum aus dem generierten html rauszuparsen wäre schon sehr unglücklich bzw. sch***e gewesen.
<?php require_once("functions.php"); $url = "https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_DWD_STAT/Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMDWD_COMMUNEUNION_DE.zip"; $headers = get_headers($url, 1); if (!$headers) exit(); $time = strtotime($headers['Last-Modified']); if (!is_dir("download_cache")) { mkdir("download_cache"); } if (!is_dir("unzip_cache")) { mkdir("unzip_cache"); } $local_file = "download_cache/".$time.".zip"; $remote_file = "Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMDWD_COMMUNEUNION_DE.zip"; if (!file_exists($local_file)) { echo "updated file '$remote_file' available<br />"; $files = glob("download_cache/*"); foreach($files as $file){ if(is_file($file)) unlink($file); } if (!file_put_contents($local_file, fopen($url, 'r'))) { exit(); } $files = glob("unzip_cache/*"); foreach($files as $file){ if(is_file($file)) unlink($file); } if(!Unzip($local_file, "unzip_cache/")) { exit(); } } else { echo "local file '$local_file' still up to date<br />"; }
Das Ganze läuft in meinem Wetterwarnungen Service bereits wie am Schnürchen. Durch die Änderung von FTP auf HTTPS wird mit Sicherheit auch die Scriptlaufzeit etwas verkürzt worden sein. Also bringt die Neuerung meines Erachtens nur Vorteile.
Hier nochmal das komplette Script:
<?php function Unzip($zipFile, $unzipDir) { echo "<br />"; echo "Unzipping '$zipFile' <br />"; $zip = new ZipArchive; $result = $zip->open($zipFile); if($result !== true){ echo "Error :- Unable to open the Zip File: $result"; return false; } /* Extract Zip File */ $zip->extractTo($unzipDir); $zip->close(); echo "Unzipped to '$unzipDir' <br /><br />"; return true; } function getLevel($info) { if ($info->urgency == "Future") return 1; switch($info->severity) { case "Minor": return 2; break; case "Moderate": return 3; break; case "Severe": return 4; break; case "Extreme": return 5; break; } } function getState($area) { $stateShort = getGeocode("STATE", $area); switch($stateShort) { case "NRW": return "Nordrhein-Westfalen"; break; case "RP": return "Rheinland-Pfalz"; break; case "BY": return "Bayern"; break; case "BW": return "Baden-Württemberg"; break; case "HE": return "Hessen"; break; case "SN": return "Sachsen"; break; case "TH": return "Thüringen"; break; case "NS": return "Niedersachsen"; break; case "HH": return "Hamburg"; break; case "HB": return "Bremen"; break; case "SH": return "Schleswig-Holstein"; break; case "SL": return "Saarland"; break; case "SA": return "Sachsen-Anhalt"; break; case "BB": return "Brandenburg"; break; case "BL": return "Berlin"; break; case "MV": return "Mecklenburg-Vorpomern"; break; } } function getGeocode($geocode, $area) { foreach($area->geocode as $code) { if ($code->valueName == $geocode){ return (string) $code->value; } } } function getEventCode($eventCode, $info) { foreach($info->eventCode as $code) { if ($code->valueName == $eventCode){ return (string) $code->value; } } } function getAltitudeStart($area) { $altCode = getGeocode("ALTITUDE", $area); switch($altCode) { case "B": return 200; case "C": return 400; case "D": return 600; case "E": return 800; case "F": return 1000; case "G": return 1500; case "H": return 2000; case "L": return 0; case "M": return 0; case "N": return 0; case "A": return 0; } } function getAltitudeEnd($area) { $altCode = getGeocode("ALTITUDE", $area); switch($altCode) { case "B": return 3000; case "C": return 3000; case "D": return 3000; case "E": return 3000; case "F": return 3000; case "G": return 3000; case "H": return 3000; case "L": return 800; case "M": return 600; case "N": return 400; case "A": return 200; } } function getAltitudeStartFromAltitude($altitude) { $result = round($altitude * 0.3048); if ($result == 0) { return null; } else { return $result; } } function getAltitudeEndFromCeiling($ceiling) { $result = round($ceiling * 0.3048); if ($result == 3000) { return null; } else { return $result; } } ?>
<?php require_once("functions.php"); $url = "https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_DWD_STAT/Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMDWD_COMMUNEUNION_DE.zip"; $headers = get_headers($url, 1); if (!$headers) exit(); $time = strtotime($headers['Last-Modified']); if (!is_dir("download_cache")) { mkdir("download_cache"); } if (!is_dir("unzip_cache")) { mkdir("unzip_cache"); } $local_file = "download_cache/".$time.".zip"; $remote_file = "Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMDWD_COMMUNEUNION_DE.zip"; if (!file_exists($local_file)) { echo "updated file '$remote_file' available<br />"; $files = glob("download_cache/*"); foreach($files as $file){ if(is_file($file)) unlink($file); } if (!file_put_contents($local_file, fopen($url, 'r'))) { exit(); } $files = glob("unzip_cache/*"); foreach($files as $file){ if(is_file($file)) unlink($file); } if(!Unzip($local_file, "unzip_cache/")) { exit(); } } else { echo "local file '$local_file' still up to date<br />"; } $alerts = array(); $files = glob("unzip_cache/*"); foreach($files as $file){ if(is_file($file)) { $xml = simplexml_load_file($file); foreach($xml->info->area as $area) { $alert['start'] = (int) strtotime($xml->info->onset) * 1000; $alert['end'] = (int) strtotime($xml->info->expires) * 1000; $alert['regionName'] = (string) $area->areaDesc; $alert['level'] = getLevel($xml->info); $alert['type'] = (string) getEventCode("GROUP", $xml->info); $alert['altitudeStart'] = getAltitudeStartFromAltitude((float) $area->altitude); $alert['event'] = (string) $xml->info->event; $alert['headline'] = (string) $xml->info->headline; $alert['description'] = (string) $xml->info->description; $alert['altitudeEnd'] = getAltitudeEndFromCeiling((float) $area->ceiling); $alert['stateShort'] = (string) getGeocode("STATE", $area); $alert['instruction'] = (string) $xml->info->instruction; $alert['state'] = getState($area); $alert['ii'] = (int) getEventCode("II", $xml->info); $alert['published'] = (int) strtotime($xml->info->effective) * 1000; $alerts['time'] = (int) strtotime(date("c")) * 1000; if ($alert['regionName'] != "polygonal event area") { if((string) $xml->info->urgency == "Immediate") { $alerts['warnings'][(string) $area->geocode[0]->value][] = $alert; } else { $alerts['vorabInformation'][(string) $area->geocode[0]->value][] = $alert; } } } } } echo "found ".count($alerts['warnings'])." warnings<br />"; echo "saving warnings to 'warnings.json'<br />"; $fp = fopen("warnings.json", "w"); fwrite($fp, json_encode($alerts, JSON_PRETTY_PRINT)); fclose($fp); echo "warnings successfully saved<br /> "; ?>
Hi,
prima Script! Habe deine vorherige Version auch schon verwendet.
Ich habe es bei mir noch etwas erweitert, um damit bei mir einen Hagelalarm frühzeitig auslösen zu können.
Hi Markus,
freut mich, dass es dir weiterhilft!
Gruß
eMpTy
Hallo und einen schönen Sonntag.
Bei mir kommt die Fehlermeldung:Warning: file_put_contents(download_cache/1505658430.zip): failed to open stream: No such file or directory in……..
Wenn ich es richtig verstehe muss ein Verzeichnis angelegt werden. Wenn dann welches?
PHP ist leider nicht meine Stärke.
Viele Grüße
Hallo Hans,
es werden zwei Unterverzeichnisse am Speicherort des Scripts benötigt:
1. download_cache
2. unzip_cache
Ich habe ein paar wenige Zeilen der update_warnings.php hinzugefügt, die die Verzeichnisse automatisch erstellen wenn nicht vorhanden.
Gruß
eMpTy
Hallo eMpTy,
vielen Dank für die schnelle Antwort.
Es funktioniert bestens.
Grüße
Hans
Hallo eMpTy,
ich hätte da mal eine Frage. Wie müsste man vorgehen um den Warnlagebericht (NRW) und Wetterbericht
über den neuen DWD Open Data Server auslesen bzw. die Txt datei abspeichern kann?
Zurzeit mache ich das über den DWD FTP Server. Dieser wird aber zum 15.01.2018 abgeschaltet.
Das ganze sieht so auf meiner Website aus: https://www.wetter-herbern.de/warnlage/index.html
Über einen Tipp oder Code Schnipsel würde ich mich sehr freuen da meine PHP Kenntnisse doch eher bescheiden sind.
Mit freundlichen Grüßen
Hans
Hallo Hans,
ich weiß leider nicht genau aus welchem Verzeichnis vom FTP-Server du die Daten bisher bekommst.
Vielleicht hilft dir diese PDF weiter, in der letzten Spalte steht, in welchem Verzeichnis vom FTP die Daten vorher zu finden waren.
Dokumentation: https://www.dwd.de/DE/leistungen/opendata/help/inhalt_allgemein/opendata_content_de_en_pdf.pdf?__blob=publicationFile
Ich vermute mal in etwa hier: https://opendata.dwd.de/weather/alerts/txt/EM/ eine der VHDL30_DWEH_XXXXXX Dateien.
Ich hoffe ich konnte helfen.
Gruß
eMpTy
Hallo,
funktioniert prima, danke.
Kann ich auch nur die Warnungen für meinen Ort in die ‚warnings.json‘ speichern lassen?
Bzw. wo muss ich diesen Filter einbauen ?
Danke
Gruß Jochen
Hallo Jochen,
in der foreach-Schleife in der update_warnings.php kannst du mit
(string) $area->geocode[0]->value == #dein Regioncode#
prüfen, ob sich die Warnung auf deine Region bezieht.
Gruß
eMpTy
Hallo,
ich habe es jetzt hinbekommen das nach der Region gesucht wird.
Aber leider werden immer noch alle Meldungen in der json Datei gespeichert.
Ist es auch möglich nur die Region zu speichern?
ich habe es so gemacht:
foreach($xml->info->area as $area) {
if((string) $area->geocode[0]->value == „808115001“) // nur Warnungen für Aidlingen
{
$alert[’start‘] = (int) strtotime($xml->info->onset) * 1000;
$alert[‚end‘] = (int) strtotime($xml->info->expires) * 1000;
$alert[‚regionName‘] = (string) $area->areaDesc;
$alert[‚level‘] = getLevel($xml->info);
$alert[‚type‘] = (string) getEventCode(„GROUP“, $xml->info);
$alert[‚altitudeStart‘] = getAltitudeStartFromAltitude((float) $area->altitude);
$alert[‚event‘] = (string) $xml->info->event;
$alert[‚headline‘] = (string) $xml->info->headline;
$alert[‚description‘] = (string) $xml->info->description;
$alert[‚altitudeEnd‘] = getAltitudeEndFromCeiling((float) $area->ceiling);
$alert[’stateShort‘] = (string) getGeocode(„STATE“, $area);
$alert[‚instruction‘] = (string) $xml->info->instruction;
$alert[’state‘] = getState($area);
$alert[‚ii‘] = (int) getEventCode(„II“, $xml->info);
$alert[‚published‘] = (int) strtotime($xml->info->effective) * 1000;
$alerts[‚time‘] = (int) strtotime(date(„c“)) * 1000;
if ($alert[‚regionName‘] != „polygonal event area“) {
if((string) $xml->info->urgency == „Immediate“) {
$alerts[‚warnings‘][(string) $area->geocode[0]->value][] = $alert;
} else {
$alerts[‚vorabInformation‘][(string) $area->geocode[0]->value][] = $alert;
}
}
}
}