Update vom 12.01.2022
Jetzt mit Details zu Dashboard-Ausgabe, inkl. Vorhersage-Chart.
Wetterdaten fürs SmartHome
Rund ums Wetter sammle ich mir eine Vielzahl an Daten aus verschiedenen Quellen. Die Wettervorhersage beziehe ich vom Norwegischen Wetterdienst yr.no, Live-Wetterdaten erhebe ich selbst oder hole sie mir über openSenseMap und Weather.com (Weather Underground) von Wetterstationen aus der Nachbarschaft. Wetterwarnungen kommen vom DWD und ein schickes Niederschlagsradar vom Wetterdienst eines (ehemals) bekannten Wetter-Moderators.
Vorgeschichte
Bisher habe ich für die Wettervorhersage via yr.no den ioBroker-Adapter genutzt. Doch seit der Umstellung der API von xml auf json ist die Anzahl der verfügbaren Werte und damit auch die Anzahl der ioBroker-Objekte explodiert – vieles davon ohne Mehrwert für mich. Dies war mir ein Dorn im Auge, versuche ich doch die Anzahl der Schreibvorgänge auf die SD-Karte klein zu halten.
Also wollte ich die API von yr.no/met.no selbst anzapfen, mit Node-RED ja kein Problem.
So mach ich es
Wenn man die API-Dokumentation aufmerksamer ließt als ich, kann man das ganze recht schnell durchschauen. (Ich brauchte dementsprechend eine Weile.) Man hat die Wahl zwischen dem classic, compact und complete Bericht. Mich interessieren die Temperaturen, die Wetterlage und die erwarteten Niederschlagsmengen. Diese bekomme ich im complete-Bericht.
Man benötigt seine Position als lat/lon. Google Maps verrät beim Rechtsklick auf jeden beliebigen Punkt der Erde die entsprechenden Werte, der erste ist dabei der Breitengrad (lat), der zweite der Längengrad (lon). Ergänzen kann man noch die Höhe über Meeresspiegel – dies ist jedoch optional.
Das Query-String für den Erfurter Dom wäre dann
https://api.met.no/weatherapi/locationforecast/2.0/complete?altitude=194&lat=50.97578937177409&lon=11.023335426472794
Es ist nötig, einen eigenen User-Agent als Identifikation bei der Anfrage mitzusenden, sonst bekommt man einen Fehler „403 Forbidden“. Hier kann man beliebig kreativ sein. Das setzen des Headers geht ganz einfach mit einem Function-Node vor dem HTTP-Request-Node:
msg.headers = { "User-Agent": "erfurter-dom-99084" } return msg;
Wenn man alles richtig gemacht hat, erhält man als Rückgabe einen wirklich umfangreichen JSON-Datensatz. Dieser enthält Vorhersagedaten für die nächsten 9 Tage. Mich interessieren tatsächlich nur die nächsten 48 Stunden. Auf weiterreichende Wetterentwicklung reagieren meine Flows nicht, und ich habe nicht den Elan, ein allzu umfangreiches Wetter-Dashboard zu bauen. Außerdem ist mir eine weitere Vorhersage eh zu sehr Wahrsagerei.
Die Auswahl der Daten
Da man die API nicht zu oft abfragen darf (und auch nicht will), sollte man die Vorhersagedaten bis zum nächsten API-Abruf zwischenspeichern. Dazu muss man sich überlegen, welche Daten man benötigt.
Beim Stöbern im JSON-Datensatz bin ich darauf gekommen, dass die interessantesten Daten für mich im Bereich der „next_6_hours“ stecken. Sowohl der Symbolcode (= die Wetterlage), als auch die Min-/Max-Temperaturen und die Niederschlagsmenge werden für diese Zeit-Korridore mitgeliefert – und das anfangs stündlich.
{
"time": "2021-08-30T15:00:00Z",
"data": {
"instant": {
"details": {
"air_pressure_at_sea_level": 1018.5,
"air_temperature": 13.8,
"cloud_area_fraction": 100,
"cloud_area_fraction_high": 57.8,
"cloud_area_fraction_low": 100,
"cloud_area_fraction_medium": 28.1,
"dew_point_temperature": 12.9,
"fog_area_fraction": 0,
"relative_humidity": 94.4,
"ultraviolet_index_clear_sky": 0,
"wind_from_direction": 355.9,
"wind_speed": 2.8
}
},
"next_12_hours": {
"summary": {
"symbol_code": "lightrain"
}
},
"next_1_hours": {
"summary": {
"symbol_code": "rain"
},
"details": {
"precipitation_amount": 0.3
}
},
"next_6_hours": {
"summary": {
"symbol_code": "lightrain"
},
"details": {
"air_temperature_max": 13.9,
"air_temperature_min": 13.1,
"precipitation_amount": 0.6
}
}
}
},
(Nicht verwirren lassen! Alle Zeitangaben sind in UTC)
Die Logik dabei ist:
Zum Zeitpunkt 30.08.2021 17:00 Uhr schaue ich mit „next_6_hours“ auf den Zeitraum zwischen 17:00 und 23:00 Uhr. Auch für den Zeitpunkt 30.08.2021 18:00 Uhr gibt es die „next_6_hours“, welche sich dann auf den Zeitraum 18:00 bis 0:00 Uhr beziehen.
Auf Kosten der Genauigkeit (die bei einer Vorhersage eh relativ ist) und zugunsten der Datensparsamkeit speichere und verarbeite ich also nur jeden sechsten Datensatz bis 42 Stunden in die Zukunft (+6 hours ergibt die 48 Stunden die ich betrachten möchte).
Für diese acht Datensätze (8*6=48 Stunden) habe ich acht Objekte im ioBroker angelegt (bei mir n0, n6, n12, n18, …), in welche ich die inzwischen von JSON in ein JavaScript Objekt konvertierten Daten der „next_6_hours“ als Objekt abspeichere.
Datenaufbereitung
Vor dem Speichern bereite ich die Daten noch ein wenig auf. Ich ordne den Symbolcodes zusätzlich die deutschen Bezeichnungen der Wetterlage zu, ergänze den Wochentag und bereite die Zeit auf, indem ich den Zeitraum errechne, für den diese Werte eine Gültigkeit haben (z.B. Dienstag, 06 – 12 Uhr). Zudem wird der Timestamp des Gültigkeitsstarts errechnet und mit abgelegt.
Nutzung der Wetterdaten
In definierten Regeln
Meine Vorhersage-Objekte (n0 – n42) sind immer aktuell, da ich die Wetterdaten einmal die Stunde abrufe. Somit weiß ich immer, im welchen Objekt welche Zeiträume stecken. Je nachdem wann ein Flow das Wetter abfragt, muss ich also nur den entsprechenden Betrachtungszeitraum festlegen.
Schaut die Rollo-Steuerung zum Beispiel um 9 Uhr, ob sie die südlichen Fenster abschatten sollte, dann schaut sie u.a. nach den Höchstwerten von „n0“, also wie warm es maximal zwischen 9 und 15 Uhr wird. Soll das Haus am Abend Bescheid sagen, dass die Fenster dank kühler Abendluft endlich geöffnet werden können, dann schaut es erst, wie warm es am nächsten und übernächsten Tag wird („n18“, „n42“).
Im Dashboard / UI
Natürlich schauen nicht nur automatische Steuerungen nach dem Wetter – ich gebe die Vorhersage auch im Dashboard aus. Neben der noch ausbaubaren tabellarischen Aufbereitung habe ich dafür inzwischen auch ein Temperatur-Vorhersage Chart.
Da ich die Daten direkt als JavaScript Objekt in das ioBroker Objekt abspeichere, kann ich auch direkt nach dem Auslesen des Objekts auf die Werte zugreifen.
msg.payload.details.air_temperature_max
Die tabellarische Ausgabe basiert somit auf einfachen Abfragen und Textausgaben, da alle Daten ja schon passend aufbereitet wurden.
Die entsprechenden ui_text – Nodes, welche durch CSS Klassen etwas gestaltet werden:
Für das Temperatur-Vorhersage-Diagramm müssen alle Objekte (iobroker list Node) geladen und daraus die passende Chart-JSON generiert werden. (siehe Flow Download)
Beispielhafte JSON zur Befüllung eines Node-RED Dashboard Charts
[{"series":["min °C","max °C"],"data":[[-0.6,-0.5,3.7,1.9,0.5,0.6,3.2,3.6],[1,2.5,5.8,3.8,1.3,2.1,5,4]],"labels":[1,7,13,19,1,7,13,19]}]
Da der abzubildende Zeitraum in der Zukunft liegt, können die Werte nicht anhand eines timestamps verortert werden, sondern brauchen feste Bezeichnungen. Hierbei habe ich mich für die Mitte des sechs Stunden Zeitraums entschieden.
Flows als Download
Wer es ausprobieren möchte, braucht im ioBroker unter 0_userdata.0.Vorhersage entsprechende Objekte und kann nach dem Import des folgenden Flows direkt loslegen.
Hi, beim mir sind im Diagramm die Vorhersage von rechts nach links. Ist etwas ungewohnt beim lesen. Ist das absicht?
Das ist eigenartig. Die Reihenfolge lässt sich aber im function-Node des „yr.no Chart 48h“ beeinflussen, indem man bei return a und b tauscht:
msg.payload.sort((a, b) => {
return b.val.startts – a.val.startts;
});
Hallo und Guten morgen.
Kannst du die „Vorhersage – Dashboard“ als „Widget“ exportiern oder kurz beschreiben?
Das würde mir bei der darstellung im VIS helfen.
mfg
Hallo Richard, ich habe den Artikel ein wenig erweitert. Ich hoffe du findest jetzt alle Antworten darin. Wenn nicht, frag gern nochmal nach. Viele Grüße!
Hey, tolle Sache deine Anleitung hier. Danke dafür. Ich wünsche auch ein guts neue Jahr! Es funktioniert.
Eine Frage habe ich noche welchen Datentyp muss ich anlegen damit beim aktualisieren der text grün und nicht rot ist?
Ändere mal im ioBroker out-Node den Type auf „value“, dann sollte ack/bestätigt = true sein und der Text nicht mehr rot. (hab es auch im Download geändert)
Danke, das klappt.