Es holt Daten aus der Wettervorhersage von AccuWeather und schreibt sie in Systemvariablen der CCU3
Was ist zu tun:
1) free API-Key beantragen: https://developer.accuweather.com/
2) Orts-ID des eigenen Orts herausfinden - in AccuWeather nach dem eigegen Ort suchen. Die Nummer am Ende der URl ist die Orts-ID. Oder man nutzt die entsprechende API
Hier z.B. 178087 für Berlin:
https://www.accuweather.com/de/de/berli ... ast/178087
Code: Alles auswählen
!-=== Hier anpassen ===
string OrtsID = "123456"; !- Hier ID für den Ort eintragen
string APIKey = "AAAAAAABBBBBBBBBBCCCCCCCCCDDDDDD"; !- Hier API-Key eintragen
string CUXD_Device = "CUxD.CUX2801001:1"; !- Hier CUxD-Device konfigurieren
3) Das Skript ruft die 12h Vorhersage ab. Ein Aufruf alle 12 Stunden wäre daher sinnvoll. Man hat 50 freie Abrufe in 24 Stunden. Wird das überschritten, gibt es keine Daten... Ändert man in den Parametern den Wert "Stunden" auf 1, dann kann man mit einem stündlichen Abruf die Daten für die jeweils nächste Stunde erhalten. Häufigere Abrufe sind allerdings recht sinnfrei! Wohlgemerkt es handelt sich um Vorhersagen, also keine aktuellen Messdaten. Dafür gibt es bei AccuWeather eine andere API, die prinzipiell mit diesem Programm auch nutzbar wäre, wenn man die URL anpasst und ggf. die Tags. Aber die 50 Abrufe pro Tag bleiben das Limit beim kostenlosen Zugang.
4) Dieses Skript einfügen und im Deklarationsteil sorgfältig anpassen.Insbesondere sind wahlweise die im Skript unter string NameSVavg0 und folgende genannten Systemvariablen anzulegen oder man trägt dort Namen bereits existierender SV ein. Existiert eine SV nicht, passiert nichts weiter, diese wird einfach ignoriert. Braucht man einen Wert nicht, dann kann man den Eintrag für die SV löschen - aber Achtung nicht das Komma löschen!
Das Skript liefert so wie es ist die Daten für Temperatur, gefühlte Temperatur, Luftfeuchtigkeit, Bewölkungsgrad und Regenmenge. Ausserdem werden in den SV FC-Timestamp-von und ...-bis der Timestamp der ersten und letzten Vorhersage abgelegt. Braucht man mehr oder weniger Daten muss man die Konfigurationsdaten anpassen. Die Konfigurationsdaten bestehen immer aus einer Auflistung, die durch Komma getrennt ist. Entsprechend wird in jeder Konfigurationsvariablen die gleiche Anzahl von Einträgen erwartet!
Code: Alles auswählen
!-=== Hier anpassen ===
integer AnzahlTags = 6; !-Anzahl der eingetragenen XML-Tags
string xmlTagStart = 'Temperature,RealFeelTemperature,RelativeHumidity,CloudCover,TotalLiquid,EpochDateTime'; !-XML-Start-Tag
string xmlTagEnd = "RealFeelTemperature,WetBulbTemperature,IndoorRelativeHumidity,MobileLink,Rain,WeatherIcon"; !-XML-End-Tag
string xmlWertStart = "Value,Value,:,:,Value,:"; !-Suchstring vor dem Wert
string xmlWertEnd = 'Unit,Unit,",",Unit,"'; !-Suchstring nach dem Wert
string xmlWertStartOffset = "7,7,1,1,7,1"; !-Länge Wert-Suchstring + Anzahl Zeichen bis zum Wert
string xmlWertEndOffset = "9,9,2,2,9,2"; !-StartOffset + Anzahl Zeichen zwischen Zahl und Ende-String
string NameSVavg0 = "Forecast_Temp_AVG,FC_feel_AVG,Forecast_Feuchte_AVG,FC_Wolken_AVG,FC_Regen_gesamt,"; !- Namen der Systemvariablen fuer Durchschnitt aktueller Tag
string NameSVmin0 = "FC_Temp_min,FC_feel_min,FC_Feuchte_min,FC_Wolken_min,FC_Regen_min,FC-Timestamp-von"; !- Namen der Systemvariablen fuer min-Wert
string NameSVmax0 = "FC_Temp_max,FC_feel_max,FC_Feuchte_max,FC_Wolken_max,FC_Regen_max,FC-Timestamp-bis"; !- Namen der Systemvariablen fuer max-Wert
integer RegenFlag = 4; !- Position der Regendaten (ab 0 zählen) zur Ausgabe der Gesamtmenge - auf 999 setzen, wenn stattdessen der Tagesdurchschnitt gewünscht ist
integer Stunden = 12; !- Anzahl der Stunden, die ausgewertet werden (min 1 / max 12)
boolean SAVE = true; !- in SV speichern: auf false für Testbetrieb, sonst true
2) xmlTagStart und xmlTagEnd: der Text, der den jeweiligen Wert im JSON einrahmt (kann man sich im Browser ansehen)
3) xmlWertStart und xmlWertEnd: Texte vor und hinter dem gesuchten Wert. Man kann - wie bei xmlWertEnd gezeigt auch nach " suchen, muss den String dann aber vorne und hinten mit ' statt wie üblich mit " einrahmen!
4) xmlWertStartOffset und xmlWertEndOffset: entsprechend anpassen, Erklärung im Quelltext
Woher weiß man, was man unter xmlTagStart oder xmlWertEnd eintragen muss? Einfach nach diesem Schema vorgehen: Siehe auch Beispiel für Wind im nächsten Beitrag!
Hier beispielsweise die Ausgabe der API. Anhand dieses Aufbaus kann man die Parameter für weitere Werte anpassen. Erweitert man die Parameter, dann muss man beachten, das der Suchstring möglichst eindeutig ist! Will man Rain auswerten, dann darf man nicht nur nach Rain suchen, da dann das vorherige RainProbability gefunden wird. Also dann nach Rain" (mit ") suchen. Hat man den gesuchten Wert sauber durch einen Suchbegriff vorher und nachher definiert, dann muss man nur noch beachten, das die Suchbegriffe für xmlWertStart und xmlWertEnd innerhalb dieses eingegrenzten Bereichs eindeutig sind. Der End-Begriff wird immer NACH dem Vorkommen des Start-Begriff gesucht. Wichtig: setzt man ein " als Suchbegriff ein, muss die gesamte Werteliste in ' (Hochkomma) statt " (Anführungszeichen) gesetzt werden, wie bei xmlWertEnd gezeigt!
Code: Alles auswählen
[
{
"DateTime": "2020-06-15T15:00:00+02:00",
"EpochDateTime": 1592226000,
"WeatherIcon": 6,
"IconPhrase": "Stark bewölkt",
"HasPrecipitation": false,
"IsDaylight": true,
"Temperature": {
"Value": 22.7,
"Unit": "C",
"UnitType": 17
},
"RealFeelTemperature": {
"Value": 23.9,
"Unit": "C",
"UnitType": 17
},
"WetBulbTemperature": {
"Value": 15.5,
"Unit": "C",
"UnitType": 17
},
"DewPoint": {
"Value": 10.7,
"Unit": "C",
"UnitType": 17
},
"Wind": {
"Speed": {
"Value": 11.1,
"Unit": "km/h",
"UnitType": 7
},
"Direction": {
"Degrees": 288,
"Localized": "WNW",
"English": "WNW"
}
},
"WindGust": {
"Speed": {
"Value": 16.7,
"Unit": "km/h",
"UnitType": 7
}
},
"RelativeHumidity": 47,
"IndoorRelativeHumidity": 47,
"Visibility": {
"Value": 16.1,
"Unit": "km",
"UnitType": 6
},
"Ceiling": {
"Value": 4359,
"Unit": "m",
"UnitType": 5
},
"UVIndex": 3,
"UVIndexText": "Mittel",
"PrecipitationProbability": 34,
"RainProbability": 34,
"SnowProbability": 0,
"IceProbability": 0,
"TotalLiquid": {
"Value": 0,
"Unit": "mm",
"UnitType": 3
},
"Rain": {
"Value": 0,
"Unit": "mm",
"UnitType": 3
},
"Snow": {
"Value": 0,
"Unit": "cm",
"UnitType": 4
},
"Ice": {
"Value": 0,
"Unit": "mm",
"UnitType": 3
},
"CloudCover": 80,
"MobileLink": "http://m.accuweather.com/de/de/sterkrade/46145/hourly-weather-forecast/170293?day=1&hbhhour=15&unit=c",
"Link": "http://www.accuweather.com/de/de/sterkrade/46145/hourly-weather-forecast/170293?day=1&hbhhour=15&unit=c"
},
z.B.
string NameSVavg0 = ",,,,,";
würde keinerlei Durchschnittswerte abspeichern
string NameSVmax0 = "Forecast_Temp,,Forecast_Feuchte,,,";
speichert Maximalwerte für Temperatur und Feuchtigkeit und sonst nichts
6) RegenFlag: Position der Regendaten in der Auflistung. Dabei startet die Zählung mit 0. Will man statt Tages-Gesamtmenge doch den Durchschnitt, oder wertet gar keinen Regen aus, dann trägt man hier 999 ein.
7) Stunden: Anzahl der Stunden, die ausgewertet werden. Die API liefert max. 12, größere Zahlen führen zu nichts. Weniger als 1 auch nicht. Will man z.B. nur die Daten der nächsten 3 Stunden wissen, trägt man dort 3 ein.
8 ) SAVE: dient zum Debugging. Insbesondere wenn man in seinen Programmen auf Änderungen der beschriebenen SV's reagiert, kann es ganz hilfreich sein, das während der Testphase nicht ständig irgendwelche Dinge triggern. Trägt man bei SAVE false ein, dann kann man unter "Skript testen" alle Debuggingausgaben sehen, ohne das die SV geändert werden! Dazu kann ich auch nur dringend beim Anpassen von Parametern raten, das ganze erst einmal im "Skript testen" Fenster laufen zu lassen, damit man den Erfolg der Maßnahmen überprüfen kann. War der Test erfolgreich, endet die Debugging-Ausgabe mit:
Code: Alles auswählen
*Temperature* avg/min/max:18.6/15.7/21.9
*RealFeelTemperature* avg/min/max:18.1/15.8/20.7
*RelativeHumidity* avg/min/max:72.1/48.0/92.0
*CloudCover* avg/min/max:94.6/82.0/98.0
*TotalLiquid* avg/min/max:0.5/0.0/0.5
*EpochDateTime* avg/min/max:1592256600.0/1592236800.0/1592276400.0
Und hier das Skript - und nochmal die Bitte: keine Support-Anfragen ohne die (als CODE formatierte) Ausgabe des Debuggings (STDOUT) und einer Kopie des Deklarationsteils des Skripts.
Code: Alles auswählen
!- aktuelle 12h-Wettervorhersage V1.1 AccuWeather universell (MichaelN 14.06.2020)
!- benötigte Systemvariablen anlegen: siehe NameSVxxx0
!-=== Hier anpassen ===
string OrtsID = "123456"; !- Hier ID für den Ort eintragen
string APIKey = "AAAAAAABBBBBBBBBBCCCCCCCCCDDDDDD"; !- Hier API-Key eintragen
string CUXD_Device = "CUxD.CUX2801001:1"; !- Hier CUxD-Device konfigurieren
!-=== Hier anpassen ===
integer AnzahlTags = 6; !-Anzahl der eingetragenen XML-Tags
string xmlTagStart = 'Temperature,RealFeelTemperature,RelativeHumidity,CloudCover,TotalLiquid,EpochDateTime'; !-XML-Start-Tag
string xmlTagEnd = "RealFeelTemperature,WetBulbTemperature,IndoorRelativeHumidity,MobileLink,Rain,WeatherIcon"; !-XML-End-Tag
string xmlWertStart = "Value,Value,:,:,Value,:"; !-Suchstring vor dem Wert
string xmlWertEnd = 'Unit,Unit,",",Unit,"'; !-Suchstring nach dem Wert
string xmlWertStartOffset = "7,7,1,1,7,1"; !-Länge Wert-Suchstring + Anzahl Zeichen bis zum Wert
string xmlWertEndOffset = "9,9,2,2,9,2"; !-StartOffset + Anzahl Zeichen zwischen Zahl und Ende-String
string NameSVavg0 = "Forecast_Temp_AVG,FC_feel_AVG,Forecast_Feuchte_AVG,FC_Wolken_AVG,FC_Regen_gesamt,"; !- Namen der Systemvariablen fuer Durchschnitt aktueller Tag
string NameSVmin0 = "FC_Temp_min,FC_feel_min,FC_Feuchte_min,FC_Wolken_min,FC_Regen_min,FC-Timestamp-von"; !- Namen der Systemvariablen fuer min-Wert
string NameSVmax0 = "FC_Temp_max,FC_feel_max,FC_Feuchte_max,FC_Wolken_max,FC_Regen_max,FC-Timestamp-bis"; !- Namen der Systemvariablen fuer max-Wert
integer RegenFlag = 4; !- Position der Regendaten (ab 0 zählen) zur Ausgabe der Gesamtmenge - auf 999 setzen, wenn stattdessen der Tagesdurchschnitt gewünscht ist
integer Stunden = 12; !- Anzahl der Stunden, die ausgewertet werden (min 1 / max 12)
boolean SAVE = true; !- in SV speichern: auf false für Testbetrieb, sonst true
!- === ab hier nichts mehr anpassen ===
!- Suchstrings und Offset-Werte zum extrahieren der Zeit
string xmlTimeStart = "EpochDateTime";
integer xmlSkip = 100;
!- XML-Antwort von OpenWeatherMaps
string recXML;
string func = "wget -q -O - 'http://dataservice.accuweather.com/forecasts/v1/hourly/12hour/"#OrtsID#"?apikey="#APIKey#"&details=true&metric=true'";
!- Arbeitsvariablen
string wert1;
string wert2;
time zeit;
integer counter; !- Sicherheitszaehler gegen Endlosschleife
integer StartPos;
integer EndPos;
integer index;
real Wert_avg;
real Wert_min;
real Wert_max;
real Wert_tmp;
object SV;
!- Diese Variablen enthalten am Schluss die Ergebnisse
string Day0_avg = "";
!- ENDE Deklarationen und Initialisierungen
!- ******************************************************************************************
!- Abruf der Daten
dom.GetObject(CUXD_Device#".CMD_SETS").State(func);
dom.GetObject(CUXD_Device#".CMD_QUERY_RET").State(1);
recXML = dom.GetObject(CUXD_Device#".CMD_RETS").State();
if(!recXML){quit;}
!- *** DEBUG recXML = dom.GetObject (ID_SYSTEM_VARIABLES).Get ("xxTest").State();
!- *** DEBUG dom.GetObject (ID_SYSTEM_VARIABLES).Get ("xxTest").State(recXML);
xmlSkip = recXML.Find(xmlTimeStart); !- ersten Block beschneiden
recXML = recXML.Substr(xmlSkip);
WriteLine(recXML);
!- Werte auslesen
counter = 0;
index = 0;
StartPos = recXML.Find(xmlTagStart.StrValueByIndex(",",0));
while ( (StartPos>=0) && (counter<100) ){
if (counter < Stunden) {
index = 0;
while ( index < AnzahlTags ) {
StartPos = recXML.Find(xmlTagStart.StrValueByIndex(",",index));
EndPos = recXML.Substr(StartPos).Find(xmlTagEnd.StrValueByIndex(",",index));
if ( EndPos == -1 )
{
EndPos = 5;
WriteLine("DEBUG Z96: EndPos nicht gefunden!");
}
EndPos = EndPos + StartPos;
wert2 = recXML.Substr(StartPos, EndPos-StartPos); !- nur das relevante Tag
WriteLine("DEBUG TAG: "#wert2);
StartPos = wert2.Find(xmlWertStart.StrValueByIndex(",",index));
EndPos = wert2.Substr(StartPos).Find(xmlWertEnd.StrValueByIndex(",",index));
if ( EndPos == -1 )
{
EndPos = 5;
WriteLine("DEBUG Z106: EndPos nicht gefunden!");
}
EndPos = EndPos + StartPos;
wert2 = wert2.Substr(StartPos+xmlWertStartOffset.StrValueByIndex(",",index).ToInteger(),(EndPos-StartPos)-xmlWertEndOffset.StrValueByIndex(",",index).ToInteger());
WriteLine("DEBUG WERT: "#wert2#" --- Start:"#StartPos#" --- End:"#EndPos);
Day0_avg = Day0_avg # wert2.ToFloat().ToString(2) # ","; !- sicherstellen das nur Zahlen geschrieben werden
!- *** DEBUG
WriteLine("c/i/w2:"#counter#"/"#index#"/"#wert2);
index = index + 1;
}
}
StartPos = recXML.Find(xmlTimeStart);
xmlSkip = StartPos+xmlTimeStart.Length(); !- abgearbeiteten Block ausschneiden
recXML = recXML.Substr(xmlSkip);
StartPos = recXML.Find(xmlTimeStart);
if ( StartPos > -1 ) { recXML = recXML.Substr(StartPos); }
!- *** DEBUG
!- WriteLine("DEBUG SKIP: c"#counter#" --- Start:"#StartPos#" --- "#recXML);
counter = counter + 1;
}
!- Werte aus Ergebnisliste fischen und wieder richtig zuordnen
counter = 0;
wert1 = "";
while ( counter < AnzahlTags ) {
index = AnzahlTags;
Wert_avg = 0.0;
Wert_min = 3000000000.0;
Wert_max = -1000.0;
EndPos = 0;
foreach(wert2,Day0_avg.Split(",")) {
if ( (index % AnzahlTags) == counter ) {
!- jeden x. Eintrag auslesen
Wert_tmp = wert2.ToFloat();
Wert_avg = Wert_avg + Wert_tmp;
EndPos = EndPos + 1;
Wert_min = Wert_min.Min(Wert_tmp);
Wert_max = Wert_max.Max(Wert_tmp);
!- *** DEBUG
WriteLine("c/i/EP/w:"#counter#"/"#index#"/"#EndPos#"/"#Wert_tmp);
}
index = index + 1;
}
!- Durchschnitt berechnen
if ( RegenFlag <> counter ) {
Wert_avg = Wert_avg/EndPos; }
!- Werte in die SV schieben
!- *** DEBUG
WriteLine("*** DEBUG Werte für SV ***");
WriteLine("--AVG--"#NameSVavg0.StrValueByIndex(",",counter)#": "#Wert_avg);
WriteLine("--MIN--"#NameSVmin0.StrValueByIndex(",",counter)#": "#Wert_min);
WriteLine("--MAX--"#NameSVmax0.StrValueByIndex(",",counter)#": "#Wert_max);
SV = dom.GetObject(ID_SYSTEM_VARIABLES).Get(NameSVavg0.StrValueByIndex(",",counter));
if ( SV && SAVE ) {SV.State(Wert_avg);}
SV = dom.GetObject(ID_SYSTEM_VARIABLES).Get(NameSVmin0.StrValueByIndex(",",counter));
if ( SV && SAVE ) {SV.State(Wert_min);}
SV = dom.GetObject(ID_SYSTEM_VARIABLES).Get(NameSVmax0.StrValueByIndex(",",counter));
if ( SV && SAVE ) {SV.State(Wert_max);}
!- *** DEBUG
wert1 = wert1 #"*"# xmlTagStart.StrValueByIndex(",",counter) #"* avg/min/max:"# Wert_avg.ToString(1) #"/"# Wert_min.ToString(1) #"/"# Wert_max.ToString(1) # "\n";
counter = counter + 1;
}
!- *** DEBUG
WriteLine(wert1);
WriteLine("===ENDE===");