← zurück zur Wetterseite

Offenes Datenarchiv · taeglich fortgeschrieben · 25 Orte, elf Modelle

Das Archiv, das diese Seite von sich selbst führt

Die Startseite prüft ihre eigenen Vorhersagen gegen echte Messungen — aber die keyless-APIs zeigen nur ein Fenster von rund sieben Tagen. Damit die Nachkontrolle über Monate reicht, legt diese Seite mehrmals täglich einen JSON-Schnappschuss ab: die heute ausgegebene Vorhersage und die echte Stationsmessung. Alles öffentlich, alles herunterladbar, alles nachrechenbar — einschließlich der Zeiten, in denen die Automatik ausgefallen ist. Die Lücken stehen weiter unten, sie werden nicht zugespachtelt. (An dieser Stelle stand bis zum 01.10.2026 „der beiden Tage, an denen die Automatik ausgefallen ist“. Es waren zwei Ausfälle, aber keine zwei Tage: Sie dauerten gut neun und gut achtzehn Tage.)

Was hier liegt — und wie es entsteht

Ein geplanter Lauf holt alle sechs Stunden (00:30, 06:30, 12:30, 18:30 UTC, jeweils versetzt hinter die Modellläufe) die keyless-Daten und schreibt statische JSON-Dateien ins Repo; Netlify liefert sie unverändert unter /data/… aus. Kein Backend, kein Schlüssel, kein Tracker — genau wie die Seite selbst. Zwei getrennte Stränge, die nie vermischt werden: die Vorhersage (elf Modelle, Open-Meteo) und die Wahrheit (echte DWD-Stationsmessung, Bright Sky). Kein Modellwert wird je als Messung ausgegeben.

Was sich wie oft ändert: forecasts/, ensemble/ und warnlage/ bekommen bei jedem Lauf eine neue Datei, und index.json wird jedes Mal neu geschrieben — also alle sechs Stunden. measured.json wird ebenfalls bei jedem Lauf neu geschrieben, neue Messwerte kommen wegen des DWD-Verzugs aber nur für einen Tag je Tag dazu: den abgeschlossenen Vortag, sobald der DWD ihn geprüft hat. Der kommt meist auf zwei Läufe verteilt an — vom 10. bis 26.09.2026 jeden Tag gleich: für 17 der 25 Städte mit dem Lauf am frühen Morgen, für die übrigen acht erst mit dem nächsten, sechs Stunden später (in diesen Tagen gegen 12:45 Uhr deutscher Zeit). Wer nur einmal am Tag abruft, holt deshalb am besten danach. Die Kurzbeschreibung dieser Seite für Suchmaschinen und Vorschaukarten sprach bis zum 30.09.2026 von „täglich einen JSON-Schnappschuss“, obwohl seit dem 19.07.2026 alle sechs Stunden gesichert wird.

Wie du dieses Archiv selbst abrufst — mit Beispielen für curl, JavaScript und Python — steht auf Daten nutzen.

Zwei Lücken im Archiv — und warum sie stehen bleiben

Wer dieses Archiv auswertet, muss von zwei Ausfällen wissen. In beiden Fällen fehlen Vorhersage-Schnappschüsse, Ensemble- und Warnlage-Stände; die Messreihe ist in beiden Fällen vollständig nachgeholt, weil sich vergangene Messtage nachträglich abrufen lassen.

Nachgezählt statt nur beschrieben

Die Liste oben ist von Hand geschrieben und veraltet, sobald die Sicherung wieder steht. Deshalb zählt diese Seite seit dem 01.10.2026 beim Laden selbst nach: jede Stelle in index.json (Feld snapshots), an der zwischen zwei gespeicherten Läufen mehr als zwölf Stunden liegen, und zuletzt der Abstand vom jüngsten Lauf bis jetzt. Die Uhrzeiten sind die Erzeugungszeiten aus dem Feld utc; oben steht teils die Startzeit aus dem Dateinamen, deshalb können beide um ein paar Minuten auseinanderliegen.

Diese Liste rechnet ein Skript aus /data/index.json; ohne JavaScript bleibt sie leer, die Datei selbst ist trotzdem abrufbar.

Beide Lücken ließen sich technisch füllen: Es gibt eine Schnittstelle, die vergangene Modellläufe zurückgibt. Die Gegenprobe an einem Tag, für den der echte Schnappschuss vorliegt, fällt aber negativ aus. Nachgemessen am 08.09.2026 gegen data/forecasts/2026-08-09T0234Z.json (Karlsruhe, Berlin, München × 11 Modelle × 8 Tage = 231 Werte): nur 3,9 % der Werte sind identisch, die Abweichung liegt im Median bei 0,80 K, im Mittel bei 1,11 K, im Einzelfall bei 7,3 K — und sie wächst mit dem Vorhersage-Horizont, von 0,30 K an Tag +1 auf 2,90 K an Tag +7. Genau dieses Muster verrät, was dort geliefert wird: nicht, was ein Modell damals sagte, sondern die später besser informierte Fassung. Wer damit auffüllte, fälschte ausgerechnet die Zahl, gegen die diese Seite ihre eigenen Vorhersagen prüft. Eine Lücke, die man sieht, ist besser als eine, die man zugespachtelt hat.

Der Stillstand im August ist nicht der einzige Fehler, den das Archiv hatte. Alle belegten Fehler der Seite — im Archiv, in den Rechnungen und im Text dieser Datenseite — stehen mit Datum und Commit im Fehlerprotokoll.

Unsere eigene Nachkontrolle — und die gemessene Historie

Aus dem eigenen Archiv, ehrlich gerechnet: sobald abgelegte Vorhersagen ihren Zieltag erreichen, vergleichen wir sie mit dem gemessenen DWD-Wert. Darunter die reine, gemessene Temperatur-Historie. Das Archiv ist eine Ergänzung — die belastbare Quelle bleibt das DWD-/API-Fenster der Startseite. Solange das eigene Archiv noch wenige Tage jung ist, steht das hier offen dabei, statt eine Zahl vorzutäuschen.

Neu: Weil wir die Vorhersage jetzt mehrmals am Tag speichern, lässt sich sehen, wie sie sich für einen Zieltag von Stand zu Stand verschiebt — das zeigt Vorhersage-Verlauf.

Unter der Messgrafik kannst du dieselben gespeicherten Werte als Tabelle öffnen. Sie zeigt bis zu 30 vorhandene Messtage, nicht zwingend 30 aufeinanderfolgende Kalendertage. Fehlende Werte bleiben fehlend; auch ein einzelner Messwert ist dort lesbar.

Archivdaten werden geladen …

Die Bestandteile des Archivs

Hier stand „Die drei Dateien“. Das stimmte einmal; inzwischen sind es mehr: Zu den drei unten beschriebenen kamen die Ensemble-Streuung (/data/ensemble/), die europäische Warnlage (/data/warnlage/) und die Klimaprojektionen (/data/klimaprojektion/). Deren Dateinamen stehen ebenfalls im Index.

Wie das Archiv aufgebaut ist — als Bild

Zwei Dinge geschehen jeden Tag. Oben: Es wird ein Vorhersage-Schnappschuss abgelegt — die an diesem Tag ausgegebene Vorhersage, acht Tage weit in die Zukunft. Am nächsten Tag kommt der nächste dazu, und der davor bleibt unverändert stehen. So stapeln sich die Schnappschüsse: nach Monaten ein Archiv. Unten: Die Messung wächst — jeden Tag kommt der echte Tageshöchstwert eines weiteren Kalendertags dazu. Beide Stränge treffen sich am heutigen Tag.

Schematischer Aufbau des Archivs Oben drei gestapelte Reihen aus je acht Zellen: tägliche Vorhersage-Schnappschuesse, die jeweils um einen Tag nach rechts versetzt in die Zukunft reichen. Unten eine Reihe der Messung, von links bis zum heutigen Tag gefuellt, danach gestrichelt und leer, weil noch nicht gemessen. Eine senkrechte Linie markiert den heutigen Tag, an dem sich Vorhersage und Messung treffen. Vorhersage — jeden Tag ein neuer 8-Tage-Schnappschuss vorgestern gestern heute 8 Tage nach vorn Messung — wächst täglich um einen Tag gemessen noch nicht gemessen heute ← früher später →
Vorhersage-Schnappschuss (8 Tage) echte Messung (gewachsen) Zukunft — noch nicht gemessen

Schematisch: zeigt nur die Anordnung der Dateien über die Zeit, keine echten Messwerte. Jede Zelle steht für einen Kalendertag.

Das Schema — versioniert

Jede Datei trägt ein schema-Feld mit Versionsnummer. Ändert sich die Form je, wächst die Nummer — alte Verbraucher merken es. Temperaturen sind °C, auf eine Nachkommastelle gerundet; null ist erlaubt (nicht jedes Modell liefert jeden Ort und Tag).

forecasts/JJJJ-MM-TT.json — wetter.kaipfstr.de/forecasts/1

{
  "schema": "wetter.kaipfstr.de/forecasts/1",
  "issued": "2026-07-18",
  "generated_utc": "2026-07-18T06:30:00Z",
  "models": ["icon_seamless", "gfs_seamless", ...],   // 11 Modelle
  "fehlend": [],                                     // seit 30.09.2026: Orte ohne Antwort
  "cities": {
    "berlin": {
      "name": "Berlin", "lat": 52.52, "lon": 13.405,
      "dates": ["2026-07-18", ...],                    // 8 Tage ab issued
      "tmax": {
        "icon_seamless": [25.5, 24.1, ...],            // 8 Werte, null erlaubt
        "gfs_seamless":  [26.6, 22.0, ...],
        ...
      }
    },
    ...
  }
}

trefferquote.json — wetter.kaipfstr.de/trefferquote/1

{
  "schema": "wetter.kaipfstr.de/trefferquote/1",
  "berechnet_utc": "2026-09-08T16:02:07Z",
  "quelle": {
    "schnappschussdateien_gesamt": 187,
    "schnappschussdateien_gewertet": 27,      // je Ausgabetag der frueheste Lauf
    "ausgabetage_gewertet": 27,
    "zieltage_von": "2026-07-18", "zieltage_bis": "2026-08-28",
    "staedte": 25, "messung": "...", "vorhersage": "..."
  },
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet: der mit der kleinsten generated_utc. ...", ...],
  "gesamt": { "paare": 5400, "treffer": 4421, "quote": 81.9,
              "median_spanne": 6.0, "median_fehlbetrag": 0.9,
              "median_mittelfehler": 1.12, "zu_kalt": 621, "zu_warm": 358 },
  "nach_vorlauf": [{ "vorlauf": 0, "paare": 675, "quote": 95.3,
                     "erwartung_ideal": 83.3, "modelle_min": 11,
                     "modelle_max": 11, "modelle_median": 11, ... }, ...],
  "rangdiagramm": { "faecher": [76, 113, 281, ..., 219, 150],
                    "paare": 2700, "modelle": 11, "erwartung_je_fach": 8.3 },
  "nach_spannenbreite": [...], "nach_stadt": [...],
  "nach_zieltag": [{ "tag": "2026-08-26", "paare": 75, "daneben": 51, "quote_daneben": 68.0,
                     "alle_zu_kalt": 13, "alle_zu_warm": 38, "orte_daneben": 24,
                     "median_fehlbetrag": 1.7, "max_fehlbetrag": 8.5 }, ...],
  "schlimmste_zieltage": [...],                  // die zehn mit dem groessten Anteil daneben
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}

Diese Datei war die erste im Archiv, die nicht gemessen oder abgerufen, sondern gerechnet ist — und zwar aus den beiden anderen. Deshalb trägt sie ihre Rechenregeln im Feld regeln mit: welcher Lauf je Ausgabetag gewertet wird, wie der Vorlauf definiert ist, dass die Spanne nur die Modelle umfasst, die für diesen Tag wirklich einen Wert geliefert haben, und dass eine Stationsmessung gegen einen Gitterpunkt verglichen wird. modelle_min und modelle_max stehen dabei, weil die Zahl der beteiligten Modelle mit dem Vorlauf sinkt — ohne sie liest man die schmalere Spanne als Einigkeit statt als Ausdünnung. erwartung_ideal ist (N−1)/(N+1) für die tatsächlich beteiligte Modellzahl, nicht pauschal für elf.

Eine Lücke, die diese Auswahl mit sich bringt (vermerkt am 30.09.2026): Wo je Ausgabetag nur ein Lauf zählt — hier, in modellprofil.json, ensemble_kalibrierung.json, faustregel.json, regenprobe.json und in der Gegenprobe von rangliste.json —, ist es immer der früheste Lauf des Tages (im Schnappschuss-Skript die Funktion _ein_lauf_je_ausgabetag und ihre älteren Geschwister). Ist genau dieser Lauf für eine Stadt unvollständig, etwa weil ihr Abruf scheiterte, fehlen dieser Stadt die Fälle des ganzen Ausgabetags — auch wenn ein späterer Lauf desselben Tages sie vollständig hat. Die Auswahlregel bleibt trotzdem, wie sie ist: Auf „den ersten vollständigen Lauf“ umgestellt, würden sich schon veröffentlichte Zahlen still verschieben. Damit solche Lücken wenigstens sichtbar werden, können Läufe künftig ein Feld fehlend tragen, das sie im Lauf selbst vermerkt — wie es die Warnlage-Stände schon tun. Wer auswertet, prüfe es, sobald es auftaucht. Ältere Läufe tragen es nicht; bei ihnen zeigt nur der Inhalt selbst, ob einer Stadt etwas fehlt.

rangliste.json — wetter.kaipfstr.de/rangliste/1

{
  "schema": "wetter.kaipfstr.de/rangliste/1",
  "berechnet_utc": "2026-09-10T11:40:12Z",
  "quelle": { "schnappschussdateien": 195, "ausgabetage": 30,
              "zieltage_von": "2026-07-18", "zieltage_bis": "2026-09-09",
              "staedte": 25, "modelle_bekannt": 11, "messung": "...", "vorhersage": "..." },
  "regeln": ["Gewertet wird JEDER archivierte Lauf, nicht nur einer je Ausgabetag ...", ...],
  "gesamt": { "vergleiche": 37400, "zieltage": 43, "max_vorlauf": 7, "konsens_mae": 1.5783 },
  "fair":   { "vergleiche": 18800, "zieltage": 35, "max_vorlauf": 3,
              "konsens_mae": 0.9071, "belastbar": true },
  "modelle": [{ "modell": "icon_seamless", "fair": 0.9594, "fair_n": 18800,
                "mae": 1.6186, "n": 33850 }, ...],       // nach "fair" sortiert
  "gegenprobe_ein_lauf_je_tag": { "schnappschussdateien": 30, "vergleiche": 5475,
                                  "laeufe_je_ausgabetag_min": 1,
                                  "laeufe_je_ausgabetag_max": 9,
                                  "reihenfolge_gleich": false,
                                  "reihenfolge": ["icon_seamless", ...], "modelle": [...] },
  "konsens_nach_vorlauf": [{ "vorlauf": 1, "mae": 0.8434, "n": 4700 }, ...],
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}

Die zweite gerechnete Datei im Archiv — und sie rechnet absichtlich anders als trefferquote.json: Dort zählt je Ausgabetag nur ein Lauf, weil die Frage „wie oft lag die Spanne richtig“ eine Frage nach Tagen ist. Hier zählt jeder Lauf, weil die Frage „wie genau ist ein Modell“ eine Frage nach Vorhersagen ist. Weil diese Wahl das Ergebnis beeinflussen kann, steht die andere Rechnung unter gegenprobe_ein_lauf_je_tag daneben — samt dem geprüften Feld reihenfolge_gleich. Es steht derzeit auf false: die Plätze zwei bis sechs tauschen, und genau dort liegen die Modelle innerhalb von 0,17 K beieinander. fair reicht strukturell nur bis Vorlauf 3, weil sie verlangt, dass jedes Modell geliefert hat und die kurzfristigen Modelle vorher aufhören — fair.max_vorlauf sagt, wie weit sie wirklich reicht.

modellprofil.json — wetter.kaipfstr.de/modellprofil/1

{
  "schema": "wetter.kaipfstr.de/modellprofil/1",
  "berechnet_utc": "2026-09-10T12:18:38Z",
  "quelle": { "schnappschussdateien_gewertet": 30, "ausgabetage_gewertet": 30,
              "zieltage_von": "2026-07-18", "zieltage_bis": "2026-09-09", "staedte": 25, ... },
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet ...", ...],
  "schlagseite": {
    "fenster": { "vergleiche": 2775, "max_vorlauf": 3, "bedingung": "..." },
    "modelle": [{ "modell": "cma_grapes_global", "bias": -3.4659, "mae": 3.5832, "n": 2775,
                  "bias_ausgabetag": -2.9828, "trend_k_pro_tag": 0.1291, "reichweite_vorlauf": 4,
                  "nach_vorlauf": [{ "vorlauf": 0, "bias": -2.9828, "n": 725 }, ...] }, ...]
  },
  "wertgleichheit": {
    "paare": [{ "a": "knmi_seamless", "b": "dmi_seamless", "vorlauf": [0, ..., 7],
                "quote": [10.1, 10.8, 87.1, 100.0, ...], "n": [750, ...] }, ...],   // alle 55
    "identisch_ab": [{ "a": "dmi_seamless", "b": "metno_seamless", "ab_vorlauf": 3, "n": 3750 }, ...]
  },
  "korrektur": { "lernen": { "ausgabetage": 15, "von": "...", "bis": "..." },
                 "pruefen": { "ausgabetage": 14, ... },
                 "gesamt": { "n": 2475, "quote_vor": 84.3, "quote_nach": 78.6 },
                 "nach_vorlauf": [{ "vorlauf": 0, "n": 350, "quote_vor": 92.9, "quote_nach": 83.7,
                                    "spanne_median_vor": 5.25, "spanne_median_nach": 3.23, ... }, ...] },
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}

Die dritte gerechnete Datei. Sie wählt wie trefferquote.json einen Lauf je Ausgabetag, weil beide Fragen nach Vorhersagesituationen fragen, nicht nach Rechenläufen. korrektur ist bewusst nicht auf denselben Tagen geschätzt und geprüft: Die Schlagseite kommt aus der ersten Hälfte der Ausgabetage, gemessen wird auf der zweiten — sonst wäre das Ergebnis zurechtgelegt. Die Zahlen im Abdruck sind der Stand vom 10.09.2026 und wandern mit jedem Schnappschuss.

ensemble_kalibrierung.json — wetter.kaipfstr.de/ensemble_kalibrierung/1

{
  "schema": "wetter.kaipfstr.de/ensemble_kalibrierung/1",
  "berechnet_utc": "2026-09-10T13:55:48Z",
  "quelle": { "ensemble_staende_gesamt": 96, "ausgabetage_gewertet": 17, "staedte": 25,
              "modell": "ecmwf_ifs025", "mitglieder": 51, ... },
  "regeln": ["Je Ausgabetag wird nur ein Stand gewertet ...", ...],
  "erwartung": { "unter_min_prozent": 1.9, "ueber_max_prozent": 1.9, "im_mittleren_band_prozent": 50.0 },
  "gesamt": { "n": 2875, "im_aeusseren_band": 88.2, "im_mittleren_band": 38.6,
              "ueber_max": 10.0, "unter_min": 1.8, "mittlerer_abstand_zum_median": 1.7, ... },
  "nach_vorlauf": [{ "vorlauf": 0, "n": 400, "im_aeusseren_band": 69.0, "im_mittleren_band": 26.0,
                     "ueber_max": 28.0, "unter_min": 3.0, ... }, ...],
  "rangdiagramm": { "faecher": ["unter_min", "min_bis_q25", ..., "ueber_max"],
                    "anzahl": [52, 621, 521, 588, 805, 288], "prozent": [1.8, 21.6, 18.1, 20.5, 28.0, 10.0] },
  "nach_streuung": { "zustand": "ok", "min_faelle_je_drittel": 30, "verhaeltnis_ideal": 1.01,
                     "ausgabetage": { "luecken": [...], ... }, "gesamt": { "schlagseite": ..., ... },
                     "regeln": [...], "nach_vorlauf": [{ "vorlauf": 0, "drittel": [...],
                     "halbierungsprobe": {...}, "verhaeltnis": ..., ... }, ...] },
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}

Die vierte gerechnete Datei, aus data/ensemble/ gegen data/measured.json. Sie ersetzt eine Rechnung, die ensemble.js bis zum 10.09.2026 im Browser machte (bis zu 60 Archivdateien je Besuch, mit stiller Obergrenze) — und sie sieht, was jene nicht sehen konnte: die Richtung. Die Messung fällt 5,6-mal so oft nach oben aus dem Fächer wie nach unten. Abdruck: Stand vom 10.09.2026. Seit dem 01.10.2026 kommt der Block nach_streuung dazu (ohne Zahlen abgedruckt, sie stehen in der Datei): je Vorlauf drei Drittel nach der Breite q75−q25 mit dem mittleren Fehler des Medians, eine Probe mit geraden und ungeraden Zieltagen und das Verhältnis aus mittlerem quadratischem Fehler und Streuung — roh und ohne Schlagseite und Ortsversatz.

warnlage_archiv.json — wetter.kaipfstr.de/warnlage_archiv/1

{
  "schema": "wetter.kaipfstr.de/warnlage_archiv/1",
  "berechnet_utc": "2026-09-11T06:30:52Z",
  "quelle": { "staende": 96, "von": "2026-07-31T13:12:37Z", "bis": "2026-09-11T04:38:55Z", "laender": 38,
              "staende_mit_fehlenden_laendern": 5, ... },
  "regeln": ["Jeder archivierte Stand zaehlt ...", ...],
  "arten_namen": { "1": "Wind", "3": "Gewitter", "5": "Hitze", ... }, "stufen_namen": { "2": "gelb", ... },
  "gesamt": { "warnungen_je_stand_min": 1591, "warnungen_je_stand_median": 5028, "warnungen_je_stand_max": 6178,
              "spitze": { "zeit": "2026-08-05T22:39:12Z", "warnungen": 6178 },
              "stufen_summe": {"2": 251798, "3": 160594, "4": 38193},
              "laender_nie_rot": ["Andorra", "Estland", "Finnland", ...], "laender_ohne_meldung": ["Malta"], ... },
  "laender": [{ "slug": "andorra", "name": "Andorra", "staende": 96, "mittel_je_stand": 10.1,
                "anteil_staende_mit_warnung": 100.0, "anteil_staende_rot": 0.0, "anteil_staende_orange": 72.9,
                "max_stufe": 3, "haeufigste_art": "Gewitter", "ohne_meldung": false }, ...],
  "staende": [{ "zeit": "2026-07-31T13:12:37Z", "gesamt": 4446, "laender_mit_warnung": 31, "fehlend": 0,
                "stufen": { ... }, "arten": { ... } }, ...],
  "license": "CC BY 4.0 (MeteoAlarm/EUMETNET)"
}

Die fünfte gerechnete Datei, aus data/warnlage/. Anders als die übrigen zählt sie jeden Stand, weil die Frage „wie oft war rot aktiv“ eine Frage nach Zeitpunkten ist und die Stände die Zeitpunkte sind. Ein Land, das in einem Stand fehlt, wird für diesen Stand nicht gewertet. ohne_meldung markiert ein Land, das in keinem Stand eine Warnung, keinen grünen Eintrag und keine Region hatte — es liefert womöglich keinen Feed und wird nicht als „warnt nie“ gezählt. Abdruck: Stand vom 11.09.2026.

tendenz.json — wetter.kaipfstr.de/tendenz/1

{
  "schema": "wetter.kaipfstr.de/tendenz/1",
  "berechnet_utc": "...",
  "quelle": { "ausgabetage_gewertet": ..., "ausgabetage_von": "...", "ausgabetage_bis": "...",
              "ausgabetage_ohne_lauf": ["...", ...], "spaete_laeufe": [{ "ausgabetag": "...",
              "generated_utc": "...", "ortszeit": "...", "nach_mittag": ... }, ...], ... },
  "grenze_k": ..., "mindestfaelle": ..., "mindest_zieltage": ...,
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet ...", ...],
  "groessen": {
    "tmax": { "zustand": "ok", "faelle": ..., "zieltage": ..., "ohne_vortag": ..., "ohne_mittel": ...,
              "vorhersage_ab_ausgabetag": "...", "messung_von": "...", "messung_bis": "...",
              "nach_vorlauf": [{ "vorlauf": 0, "zustand": "ok", "faelle": ..., "zieltage": ...,
                                 "mittlere_abweichung_gemessen": ..., "quote": { "vorhersage": ...,
                                 "immer_ueber": ..., "abweichung_bleibt": ... },
                                 "vorsprung_pp": {...}, "vorsprung_spanne95_pp": {...},
                                 "vorhersage_daneben": {...}, "matrix_vorhersage_gegen_gemessen": {...},
                                 "faelle_aus_spaeten_laeufen": ..., "faelle_je_monat": {...} }, ...],
              "gleiche_zieltage": { "paare": ..., "nach_vorlauf": [...] },
              "versatz": { "staedte": [{ "slug": "...", "mittlere_abweichung_gemessen": ...,
                           "mittlere_abweichung_vorhersage": ..., "stationsanteil_k": ... }, ...],
                           "spanne_k": ..., "spanne_stationsanteil_k": ... } },
    "tmin": { "zustand": "waechst", ... } },
  "license": "CC BY 4.0 (Open-Meteo, ERA5) / DWD GeoNutzV (Messung)"
}

Seit dem 01.10.2026. Ordnet Vorhersage und Messung je Fall einer Klasse zu — unter, nahe oder über dem ERA5-Gittermittel des Kalendertags — und vergleicht die Trefferquote mit zwei faulen Regeln („wird eh wärmer“, „Abweichung bleibt“), nur innerhalb eines Vorlaufs. Der Vorsprung hat eine 95-%-Spanne aus Ziehungen ganzer Zieltage. Abgedruckt ohne Zahlen; sie stehen in der Datei. Ausgewertet auf Faustregel.

trefferquote_tmin.json — wetter.kaipfstr.de/trefferquote_tmin/1

{
  "schema": "wetter.kaipfstr.de/trefferquote_tmin/1",
  "berechnet_utc": "...", "mindestzahl": ..., "mindest_naechte": ...,
  "quelle": { "schnappschussdateien_mit_tmin": ..., "ausgabetage_gewertet": ...,
              "erster_gewerteter_ausgabetag": "...", "zieltage_von": "...", "zieltage_bis": "...", ... },
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet ...", ...],
  "gesamt": { "zustand": "waechst", "faelle": ..., "naechte": ..., "fehlen_bis_mindestzahl": ...,
              "fehlen_naechte": ..., "mindestzahl_fruehestens_mit_messung_vom": ..., "quote": null,
              "schlagseite": null, "mae": null, "faelle_je_vorlauf": {...}, ... },
  "nach_vorlauf": [{ "vorlauf": 0, ... }, ...], "nach_stadt": [{ "slug": "...", ... }, ...],
  "tag_gegen_nacht": { "zustand": "...", "mae_tmin": ..., "mae_tmax": ..., "differenz_spanne95": ... },
  "luecken": { "tmin_vorhersage_seit": {...}, "ausgabetage_ohne_tmin": [...],
               "tmin_messung_von": "...", "tmin_messung_bis": "...", "staedte_ohne_tmin_messung": [...],
               "tage_mit_tmax_ohne_tmin": [...], "quellenpruefung_je_wert_seit": "...",
               "v0_spaete_laeufe": [...], "v0_ausgeschlossen": ... },
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}

Seit dem 01.10.2026, getrennt von trefferquote.json, damit sich die Höchstwert-Zahlen nicht still verschieben. Die Datei entsteht auch unter der Mindestzahl — dann mit zustand auf waechst, ohne Quote, aber mit dem Lückenbericht. Abgedruckt ohne Zahlen; sie stehen in der Datei.

extremtage.json — wetter.kaipfstr.de/extremtage/1

{
  "schema": "wetter.kaipfstr.de/extremtage/1",
  "berechnet_utc": "...",
  "quelle": { "faelle": ..., "ausgabetage_gewertet": ..., "luecken_ausgabetage": [["...", "..."], ...],
              "spaete_laeufe": [...], ... },
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet ...", ...],
  "schwelle_c": ..., "anomalie_schwelle_k": ..., "mindestfaelle": ...,
  "nach_vorlauf": [{ "vorlauf": 0, "faelle": ..., "zieltage": ..., "faelle_aus_spaeten_laeufen": ...,
                     "ohne_spaete_laeufe": {...},
                     "alle": { "mittlere_abweichung": ..., "spanne95": [..., ...], "mae": ... },
                     "nach_messung": { "zustand": "ok", "n": ..., "zieltage": ..., "episoden": ...,
                                       "mittlere_abweichung": ..., "spanne95": [..., ...], ... },
                     "nach_ansage": {...}, "beide_heiss": {...}, "tafel": {...},
                     "weit_ueber_ueblich": {...}, "gegenprobe": {...} }, ...],
  "gleiche_zieltage": { "paare": ..., "nach_vorlauf": [...] },
  "nicht_pruefbar": { "hitzetage_gemessen": ..., "davon_geprueft": ..., "vor_archivbeginn": ...,
                      "in_archivluecke": ..., "sonstiger_grund": ..., "hoechste_vor_archivbeginn": [...] },
  "amtlicher_rekord": {...}, "quellenpruefung_je_wert_seit": "...",
  "license": "CC BY 4.0 (Open-Meteo, ERA5) / DWD GeoNutzV (Messung)"
}

Seit dem 01.10.2026. Hitzetage in zwei Blickrichtungen — gefiltert nach der Messung (zum guten Teil Auswahl, Regression zur Mitte) und nach der Ansage (bei einer kalibrierten Vorhersage im Mittel null) —, mit Spannen aus Ziehungen ganzer Zieltage, der Zahl der Hitzewellen dahinter und einer Gegenprobe auf gleichen Zieltagen. Der amtliche Rekord steht als Bezug in der Datei, er stammt nicht aus dem Archiv. Abgedruckt ohne Zahlen; sie stehen in der Datei.

ortsbilanz.json — wetter.kaipfstr.de/ortsbilanz/1

{
  "schema": "wetter.kaipfstr.de/ortsbilanz/1",
  "berechnet_utc": "...",
  "quelle": { "ausgabetage_gewertet": ..., "luecken": [{ "von": "...", "bis": "...", "tage": ... }, ...],
              "spaete_laeufe": [...], ... },
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet ...", ...],
  "mindestfaelle": ..., "gruppen": [{ "schluessel": "nah", "vorlauf_von": 0, "vorlauf_bis": 1, ... }, ...],
  "groessen": {
    "tmax": { "zustand": "bereit", "faelle": ..., "gesamt": {...}, "spannweite": {...},
              "halbierungsprobe": { "zeitlich": { "nah": { "r": ..., "spearman": ..., "niveau_a": ...,
                                    "niveau_b": ..., "mittlere_aenderung_k": ..., ... }, ... }, ... },
              "rangliste_fair": { "gesamtsieger": "...", "gesamt_zweiter": "...", "gesamt_abstand_k": ...,
                                  "gesamtsieger_haelften": {...}, "gleichstand_k": ..., "knappe_siege": ...,
                                  "siege": [...], "halbierung": {...}, ... },
              "nach_stadt": [{ "slug": "...", "stationen": [{ "name": "...", "distance_km": ... }],
                               "nah": { "bias": ..., "mae": ... }, "alle": {...}, "haelften": {...},
                               "fair": { "sieger": "...", "abstand_k": ..., "knapp": ..., ... } }, ...] },
    "tmin": { "zustand": "waechst", ... } },
  "license": "CC BY 4.0 (Open-Meteo, ERA5) / DWD GeoNutzV (Messung)"
}

Seit dem 01.10.2026. Die Nachkontrolle nach Orten: Versatz des Konsenses gegen die Station je Stadt, eine Halbierungsprobe nach Zieltagen (Korrelation, Rangkorrelation und das Niveau je Hälfte) und je Stadt der Sieger der gleichen Aufgabe — Siege unter gleichstand_k zählen als knapp. Abgedruckt ohne Zahlen; sie stehen in der Datei.

monatsbilanz.json — wetter.kaipfstr.de/monatsbilanz/1

{
  "schema": "wetter.kaipfstr.de/monatsbilanz/1",
  "berechnet_utc": "...",
  "quelle": { "ausgabetage_archiviert": ..., "ausgabetage_mit_vergleich": ..., "fehlende_ausgabetage": [...],
              "spaete_laeufe": [...], "messung_bis": "...", "paare": ..., ... },
  "mindestfaelle": ..., "mindest_zieltage": ..., "min_orte_zieltag": ...,
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet ...", ...],
  "monate": [{ "monat": "JJJJ-MM", "zieltage": ..., "mittlerer_vorlauf": ...,
               "luecken": [{ "von": "...", "bis": "...", "tage": ..., "grund": "ausfall" }, ...],
               "roh": { "paare": ..., "quote": ..., "mae": ..., "schlagseite": ... },
               "vorlaufbereinigt": { "zustand": "gewertet", "mae": ..., "mae_spanne95": [..., ...], ... },
               "gleiche_zieltage": {...},
               "nach_vorlauf": [{ "vorlauf": 0, "zustand": "gewertet", "paare": ..., "zieltage": ...,
                                  "mae": ..., "schlimmster_zieltag": {...}, ... }, ...] }, ...],
  "vergleiche": [{ "von": "JJJJ-MM", "nach": "JJJJ-MM", "roh_differenz_k": ..., "roh_spanne95": [...],
                   "bereinigt_differenz_k": ..., "bereinigt_spanne95": [...], "mixeffekt_k": [..., ...] }, ...],
  "stationsabstand_era5": { "fenster_tage": ..., "monate": [{ "monat": "...", "tage": ..., "mittel_k": ... }, ...] },
  "license": "CC BY 4.0 (Open-Meteo, ERA5) / DWD GeoNutzV (Messung)"
}

Seit dem 01.10.2026. Das Zeugnis je Zielmonat und je Vorlauf — weil die Lücken im Archiv von Monat zu Monat verschieben, wie viele Vergleiche auf kurze und lange Vorläufe fallen. Die Spannen stammen aus Ziehungen ganzer Zieltage; mixeffekt_k ist der Teil des rohen Unterschieds zweier Monate, der allein aus dem anderen Vorlaufmix folgt. Abgedruckt ohne Zahlen; sie stehen in der Datei.

spruenge.json — wetter.kaipfstr.de/spruenge/1

{
  "schema": "wetter.kaipfstr.de/spruenge/1",
  "berechnet_utc": "...",
  "quelle": { "ausgabetage_gewertet": ..., "ausgabetage_luecken": [{ "von": "...", "bis": "...", "tage": ... }],
              "spaete_laeufe": [...], "messung_bis": "...", ... },
  "regeln": ["Je Ausgabetag wird nur ein Lauf gewertet ...", ...],
  "mindestfaelle": ..., "bootstrap": { "ziehungen": ..., "block": "Zieltag" },
  "vergleich_gegenbewegung": { "neue_information_prozent": ..., "unabhaengig_gleich_verteilt_prozent": ... },
  "nach_vorlauf": [{ "vorlauf": 0, "von_vorlauf": 1,
                     "sprung": { "zustand": "fertig", "n": ..., "median_k": ..., "q90_k": ..., ... },
                     "gegenbewegung": { "gegen_prozent": ..., "gegen_spanne95": [..., ...], "gross_ab_k": ...,
                                        "nach_grossem_gegen_prozent": ..., ... },
                     "richtung": { "waermer_naeher_prozent": ..., "kaelter_naeher_prozent": ...,
                                   "ohne_schlagseite": {...}, ... },
                     "mittel_heute_gestern": { "gewinn_k": ..., "gewinn_spanne95": [..., ...], ... },
                     "drittel": { "gruppen": [...], "gross_minus_klein_k": ..., "gross_minus_klein_spanne95": [...] },
                     "eine_stimme": { "sprung_median_k": ..., "gegen_prozent": ... },
                     "dubletten_gleich_prozent": ... }, ...],
  "je_modell": [{ "modell": "ecmwf_ifs025", "nach_vorlauf": [...] }, ...],
  "beispiel": { "slug": "...", "zieltag": "...", "drei_staende": [...], "alle_staende": [...] },
  "innerhalb_des_tages": { "nach_vorlauf": [{ "vorlauf": 1, "differenz_k": ..., "differenz_spanne95": [...] }, ...] },
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}

Seit dem 01.10.2026. Wie die Vorhersage für denselben Tag von Lauf zu Lauf springt und ob ein Sprung zur Messung führt. Die Spannen stammen aus Ziehungen ganzer Zieltage, weil viele Städte an einem Tag gemeinsam springen; eine_stimme rechnet die Kernzahlen mit KNMI, DMI und MET Norway als einer Stimme nach. Abgedruckt ohne Zahlen; sie stehen in der Datei.

measured.json — wetter.kaipfstr.de/measured/1

{
  "schema": "wetter.kaipfstr.de/measured/1",
  "updated_utc": "2026-07-18T06:31:00Z",
  "source": "Bright Sky (DWD historical)",
  "cities": {
    "berlin": {
      "name": "Berlin",
      "station": { "name": "Berlin-Friedrichshain/Spree",       // Station des juengsten Tages
                   "dwd_station_id": "17473", "distance_km": 1.9 },
      "stationen": [ { "name": "Berlin-Friedrichshain/Spree",    // alle je gesehenen
                       "dwd_station_id": "17473", "distance_km": 1.9 } ],
      "tmax": { "2026-05-18": 20.0, ..., "2026-07-16": 29.4 },  // waechst
      "tmin": { ... }, "niederschlag": { ... },                  // seit 26.09.2026
      "temperatur_fehlstunden": { "JJJJ-MM-TT": [3, 4], ... }   // seit 01.10.2026
    },
    ...
  }
}

temperatur_fehlstunden nennt je Tag die Stunden (Ortszeit), für die die nächste Station keinen eigenen Temperaturwert hatte — nur für unvollständige Tage. Ein Höchstwert gilt schon, sobald eine eigene Stunde ab 16 Uhr dabei ist; hier sieht man, ob er aus einem lückenhaften Tag stammt. Für Tage, die vor dem 01.10.2026 zuletzt abgerufen wurden, hält das Archiv das nicht fest.

verlauf/<ort>.json — wetter.kaipfstr.de/verlauf/1

{
  "schema": "wetter.kaipfstr.de/verlauf/1",
  "berechnet_utc": "2026-09-30T20:16:25Z",
  "slug": "karlsruhe", "name": "Karlsruhe",
  "quelle": { "laeufe": 266, "erster_lauf": ["2026-07-18T09:25Z", "2026-07-18"], ... },
  "regeln": ["...", ...],                      // die Rechenregeln im Klartext
  "felder_lauf":  ["utc", "ausgabe"],
  "felder_stand": ["lauf", "vorlauf", "median", "modelle", "verschieden"],
  "laeufe": [["2026-07-18T09:25Z", "2026-07-18"], ...],   // sortiert nach utc
  "zieltage": {
    "2026-10-03": { "staende": [[256, 7, 18.3, 7, 5], ...] },
    "2026-09-26": { "staende": [...], "gemessen": 26.7 },  // sobald gemessen
    ...
  }
}

Ein Stand verweist mit lauf auf seine Zeile in laeufe, damit die Zeitangabe nicht in jedem Stand wiederholt wird. Der Median ist wie auf der Seite auf eine Nachkommastelle gerundet.

index.json — wetter.kaipfstr.de/index/1

{
  "schema": "wetter.kaipfstr.de/index/1",
  "updated_utc": "2026-07-18T06:31:00Z",
  "cities":  [{ "slug": "berlin", "name": "Berlin", "lat": 52.52, "lon": 13.405 }, ...],
  "models":  ["icon_seamless", ...],
  "forecasts": ["2026-07-18", ...],           // Ausgabetage, KEINE Dateinamen
  "snapshots": [{ "file": "2026-08-01T0630Z.json", "date": "2026-08-01",
                  "utc": "2026-08-01T06:30Z" }, ...],   // hier steht der Dateiname
  "ensembles": [{ "file": "...", "date": "...", "utc": "..." }, ...],
  "warnlagen": [{ "file": "...", "date": "...", "utc": "..." }, ...],
  "klimaprojektionen": [{ "file": "karlsruhe.json", "slug": "karlsruhe",
                          "erzeugt": "2026-08-01T...Z", "modelle": 7,
                          "nachkommastellen": 2 }, ...],
  "verlauf": [{ "file": "karlsruhe.json", "slug": "karlsruhe",
                "berechnet_utc": "2026-09-30T...Z", "laeufe": 266 }, ...],
  "measured": "/data/measured.json",
  "trefferquote": "/data/trefferquote.json",
  "rangliste": "/data/rangliste.json",
  "modellprofil": "/data/modellprofil.json",
  "ensemble_kalibrierung": "/data/ensemble_kalibrierung.json",
  "warnlage_archiv": "/data/warnlage_archiv.json",
  "klimatologie": "/data/klimatologie.json",
  "faustregel": "/data/faustregel.json",
  "tendenz": "/data/tendenz.json",
  "ortsbilanz": "/data/ortsbilanz.json",
  "monatsbilanz": "/data/monatsbilanz.json",
  "spruenge": "/data/spruenge.json",
  "trefferquote_tmin": "/data/trefferquote_tmin.json",
  "regenprobe": null,                         // null, solange die Datei fehlt
  "extremtage": "/data/extremtage.json",
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}

Drei Felder fehlten hier bis zum 30.09.2026, obwohl der Index sie führte: klimatologie, faustregel und regenprobe — derselbe Fehler wie der, den der nächste Absatz schon einmal eingesteht. regenprobe stand am 30.09.2026 auf null, weil die Datei noch nicht entstanden war. Das gilt für alle vorab gerechneten Felder von trefferquote bis regenprobe: Solange ihre Datei nicht existiert, steht dort null statt einer Adresse. Prüfe darauf, bevor du abrufst.

verlauf ist am 30.09.2026 dazugekommen. Der Index, der am 30.09.2026 im Archiv lag, stammte noch vom 28.09. und führte das Feld deshalb noch nicht; es erscheint mit dem ersten Schnappschuss danach. Die Dateien selbst liegen schon unter /data/verlauf/.

Vier dieser Felder fehlten hier bis zum 01.08.2026, obwohl der Index sie längst führte: snapshots, ensembles, warnlagen und klimaprojektionen. Der Abdruck versprach eine Form, die knapper war als die echte — und ausgerechnet snapshots ist das Feld, aus dem man den Dateinamen nimmt. klimaprojektionen hat ein anderes Namensschema als die übrigen: eine Datei je Ort statt je Lauf, weil sich Projektionen nicht ändern.

Ein echter Ausschnitt — damit man es sieht

Kein erfundenes Beispiel: Die folgenden Ausschnitte stammen unverändert aus den Dateien, die am 18. Juli 2026 unter /data/… lagen — nur gekürzt (die … stehen für die übrigen Orte, Modelle und Tage). So sehen die Daten wirklich aus, am Beispiel Berlin.

echter Ausschnitt

/data/index.json — das Verzeichnis

{
  "schema": "wetter.kaipfstr.de/index/1",
  "updated_utc": "2026-07-18T09:27:26Z",
  "cities": [
    { "slug": "berlin",  "name": "Berlin",  "lat": 52.52,   "lon": 13.405 },
    { "slug": "hamburg", "name": "Hamburg", "lat": 53.5507, "lon": 9.993 },
    ...                                        // 25 Orte insgesamt
  ],
  "models": ["icon_seamless", "gfs_seamless", "ecmwf_ifs025", ...],  // 11 Modelle
  "forecasts": ["2026-07-18"],                 // bisher genau ein Ausgabetag
  "measured": "/data/measured.json",
  "trefferquote": "/data/trefferquote.json",
  "license": "CC BY 4.0 (Open-Meteo) / DWD GeoNutzV (Messung)"
}
echter Ausschnitt

/data/measured.json — die echte Messung

{
  "schema": "wetter.kaipfstr.de/measured/1",
  "updated_utc": "2026-07-18T09:27:26Z",
  "source": "Bright Sky (DWD historical)",
  "cities": {
    "berlin": {
      "name": "Berlin",
      "station": { "name": "Berlin-Friedrichshain/Spree",
                   "dwd_station_id": "17473", "distance_km": 1.9 },
      "tmax": {
        "2026-05-18": 20.0,
        ...
        "2026-07-14": 25.6,
        "2026-07-15": 25.1,
        "2026-07-16": 29.4
      }
    },
    ...                                        // 25 Orte
  }
}
echter Ausschnitt

/data/forecasts/2026-07-18.json — der Schnappschuss

{
  "schema": "wetter.kaipfstr.de/forecasts/1",
  "issued": "2026-07-18",
  "generated_utc": "2026-07-18T09:25:28Z",
  "models": ["icon_seamless", "gfs_seamless", "ecmwf_ifs025", ...],
  "cities": {
    "berlin": {
      "name": "Berlin", "lat": 52.52, "lon": 13.405,
      "dates": ["2026-07-18", "2026-07-19", "2026-07-20", "2026-07-21",
                "2026-07-22", "2026-07-23", "2026-07-24", "2026-07-25"],
      "tmax": {
        "icon_seamless": [25.5, 24.1, 17.7, 24.2, 18.1, 22.4, 24.7, null],
        "gfs_seamless":  [26.6, 22.0, 18.6, 23.8, 20.0, 20.8, 24.0, 27.8],
        ...                                    // 11 Modelle
      }
    },
    ...                                        // 25 Orte
  }
}

So liest man das zusammen: In measured.json steht für Berlin am 16. Juli der echte Tageshöchstwert 29,4 °C, gemessen an der Station Berlin-Friedrichshain, 1,9 km vom Stadtpunkt. Im Schnappschuss vom 18. Juli sagt das Modell gfs_seamless für den letzten der acht Tage (25. Juli) 27,8 °C voraus — während icon_seamless für denselben Tag null liefert: dieses Modell reicht nicht so weit, und der Platz bleibt ehrlich leer statt geraten. Genau diese Paare — später ausgegebene Vorhersage gegen später gemessene Wahrheit — sind der Stoff, aus dem der Feldbericht seine Fehlerkurven rechnet.

Auch ohne Programmieren: Datei öffnen und lesen

Man braucht kein Skript. Eine .json-Datei ist reiner Text — jeder Browser und jeder Texteditor zeigt sie an. So kommt man ran:

Womit man loslegen kann, ohne eine Zeile Code: nachschauen, wie warm es an einem bestimmten Tag in der eigenen Stadt wirklich war; zwei Modelle für denselben Tag nebeneinanderhalten und sehen, wie weit sie auseinanderliegen; oder sich ein kleines Wetter-Tagebuch abschreiben. Wer doch programmiert, findet die Skizze weiter unten.

Wofür es gut ist: die 7-Tage-Grenze überspringen

Die keyless-Vorhersage- und Messungs-APIs zeigen nur ein schmales Fenster. Dieses Archiv hält beide Seiten fest, Tag für Tag — und erst dadurch kann man über Wochen und Monate nachrechnen, wie gut die Vorhersage wirklich war.

Ein Nachkontroll-Zeitraum, so lang wie das Archiv: Nimm aus einer alten forecasts/JJJJ-MM-TT.json die an dem Tag für ein späteres Datum ausgegebene Vorhersage (z. B. der Wert für issued + 3 Tage) und stell ihm aus measured.json den echten Tageshöchstwert desselben Datums gegenüber. Der Betrag der Differenz ist der Fehler dieser Vorhersage bei drei Tagen Vorlauf. Über viele Ausgabetage gemittelt entsteht dieselbe Fehler-nach-Vorlauf-Kurve wie im Feldbericht — nur eben so weit zurück, wie das Archiv reicht, statt nur sieben Tage.

Skizze (Python, nur Standardbibliothek)

import json, urllib.request

def hol(pfad):
    with urllib.request.urlopen("https://wetter.kaipfstr.de" + pfad) as r:
        return json.load(r)

idx      = hol("/data/index.json")
messung  = hol("/data/measured.json")["cities"]

# Fehler bei 3 Tagen Vorlauf fuer Berlin, ueber alle Ausgabetage:
fehler = []
for tag in idx["forecasts"]:
    fc = hol("/data/forecasts/%s.json" % tag)["cities"]["berlin"]
    if len(fc["dates"]) <= 3:
        continue
    ziel = fc["dates"][3]                         # issued + 3 Tage
    vorh = fc["tmax"]["icon_seamless"][3]         # ein Modell als Beispiel
    echt = messung["berlin"]["tmax"].get(ziel)
    if vorh is not None and echt is not None:
        fehler.append(abs(vorh - echt))

print("MAE @3 Tage:", round(sum(fehler) / len(fehler), 2), "K  (n =", len(fehler), ")")

Ehrlich dazu: Das Vorhersage-Archiv beginnt mit dem Tag, an dem es eingerichtet wurde, und wächst von da an — die damalige 8-Tage-Vorhersage lässt sich nicht glaubwürdig rückwirkend rekonstruieren, also wird sie es auch nicht. Die Messung dagegen ist ab Start rund 60 Tage tief (echte DWD-historical). Anfangs gibt es also mehr Wahrheit als Vorhersage; die Vorhersageseite holt Tag für Tag auf.

Die 25 Orte

Regional verteilt über Deutschland. Der Slug (kleingeschrieben, ohne Umlaute) ist der Schlüssel in allen Dateien des Archivs.

Wie die Zahlen entstehen — zum Nachprüfen

Vorhersage (je Ort, alle elf Modelle in einem Aufruf, 8 Tage, Höchst- und Tiefstwert, Niederschlagssumme):

https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.405&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&models=icon_seamless,gfs_seamless,ecmwf_ifs025,gem_seamless,ukmo_seamless,meteofrance_seamless,jma_seamless,knmi_seamless,dmi_seamless,metno_seamless,cma_grapes_global&forecast_days=8&timezone=Europe%2FBerlin

Messung (echte DWD-Station, Tageshöchstwert aus den Stundenwerten der nächsten historical-Station; nur vollständig gemessene Tage zählen):

https://api.brightsky.dev/weather?lat=52.52&lon=13.405&date=2026-07-14&last_date=2026-07-16T23:59&tz=Europe/Berlin&units=dwd&observation_type=historical

Aus den Stundenwerten je Kalendertag das Maximum bilden — das ist der Tageshöchstwert. Für die Messung zählt ausschließlich die nächstgelegene Station mit observation_type = historical (qualitätsgeprüfte DWD-Messung), nie current (roh) und nie forecast (Modell).

Wichtig, weil ehrlich: Der DWD prüft die Stunden eines Tages nicht sofort, sondern nach und nach. Für die letzten ein, zwei Tage kann der Nachmittags-Peak noch nicht als historical freigegeben sein — dann liegt der hier gespeicherte Tageshöchstwert vorübergehend ein paar Zehntelgrad zu niedrig, bis der DWD den Tag final prüft. Wir nehmen bewusst den geprüften Wert und nicht den rohen. Der tägliche Lauf holt die letzten 14 Tage jedes Mal neu und überschreibt sie mit dem Endwert. (Genauer: jeder Lauf, also alle sechs Stunden. „Der tägliche Lauf“ stammt aus der Zeit bis zum 19.07.2026, als nur einmal am Tag gesichert wurde.) Anders gesagt: Sogar die „Messung" wird nachrevidiert — genau die Art Unsicherheit, die diese Seite sichtbar macht, statt sie zu verstecken.

Lizenz & Attribution

Die Vorhersage stammt von Open-Meteo und steht unter CC BY 4.0. Die Messung ist eine DWD-Stationsmessung, bezogen über Bright Sky, und unterliegt der DWD GeoNutzV (Quelle: Deutscher Wetterdienst). Verwendest du die Daten weiter, nenne diese Quellen. Das Archiv selbst ist frei nutzbar unter denselben Bedingungen — lade es herunter, rechne nach, bau etwas damit.