HM-Script für virtuelle Wetterstation

User stellen ihre Haussteuerung vor

Moderator: Co-Administratoren

MartinBr
Beiträge: 160
Registriert: 25.01.2017, 10:51
Wohnort: Bei Berlin

Re: HM-Script für virtuelle Wetterstation

Beitrag von MartinBr » 22.02.2017, 16:54

Hallo,
kann man das Script auch um den Niederschlag (Regen / Schnee) erweitern? Oder noch den Wetter Forecast?

Tolle Idee mit dem Wrapper Device! Hat alles super geklappt. Ich habe nun alle meine Scripts mit tmp Variablen geschrieben, ich war auch bei ca. 270!!!
Gruß
Martin
RaspberryMatic 3.41.11.20181124 auf TinderBoard S, CUxD 2.10, XML-1.19, ioBroker unter Debian 9, Alexa mit ioBroker, VitoComfort 200

gentoo79
Beiträge: 48
Registriert: 14.02.2016, 13:06

Re: HM-Script für virtuelle Wetterstation

Beitrag von gentoo79 » 24.02.2017, 05:45

Mal eine Frage , würde man es auch hin bekommen das bei Pocket control Bild

Windgeschwindigkeit und Windrichtung angezeigt wird ?


Gesendet von iPhone mit Tapatalk
LG
Gentoo79
  • --------------------------------------------
    102 Kanäle in 34 Geräten und 94 CUxD-Kanäle in 14 CUxD-Geräten:

OffroadXC
Beiträge: 13
Registriert: 01.04.2016, 19:36

Re: HM-Script für virtuelle Wetterstation

Beitrag von OffroadXC » 26.02.2017, 21:13

Hallo DimMyPrp,

vielen Dank für deine Projektvorstellung! Dies ist eine gute Alternative zur eigenen Investition in eine Wetterstation :-)
Ich hatte aber bei einigen Variablen keine Werte vorliegen und habe mich mal etwas mit der XML-Antwort von OpenWeatherMap auseinandergesetzt.
Dabei habe ich in deinem Script ein paar kleine (Schreib-)Fehler gefunden! Dadurch bleiben mehrere Variablen leer.

Ab ca. Zeile 195

!Suchstrings für XML-Tags von Exec festlegen
xmlStartTagName_Aktualisierung = '<lastupdate ';
xmlEndTagName_Aktualisierung = '>';
xmlStartTagName_Temperatur = '<humidity '; hier ist ein Fehler - Richtig ist xmlStartTagName_Temperatur = '<temperature ';
xmlEndTagName_Temperatur = '>';
xmlStartTagName_Luftfeuchtigkeit = '<humidity ';
xmlEndTagName_Luftfeuchtigkeit = '>';
xmlStartTagName_Luftdruck = '<pressure ';
xmlEndTagName_Luftdruck = '>';
und der Tag "wind" ist anders aufgebaut
xmlStartTagName_Wind = '<wind '; - Richtig ist xmlStartTagName_Wind = '<wind>';
xmlEndTagName_Wind = '>'; - Richtig ist xmlStartTagName_Wind = '</wind>';
xmlStartTagName_Geschwindigkeit = '<speed ';
xmlEndTagName_Geschwindigkeit = '>';
xmlStartTagName_Windrichtung = '<direction ';
xmlEndTagName_Windrichtung = '>';
xmlStartTagName_Stadt = '<city ';
xmlEndTagName_Stadt = '>'; - Richtig ist xmlEndTagName_Stadt = '</city>';
xmlStartTagName_Sonnezeit = '<sun '; - Richtig ist xmlStartTagName_Sonnenzeit = '<sun '; (da hat ein "n" bei Sonnenzeit gefehlt)
xmlEndTagName_Sonnenzeit = '>';

So funktioniert bei mir dann alles!

Viele Grüße aus Sachsen

Hier noch einmal der vollständige Code:

Code: Alles auswählen

!OpenWeather-CCU-Script, Version 1, 15.02.2017, dimmyprp

!Hier den API-Key von OpenWeather eintragen bzw. den vorhanden Key austauschen.
!Dieser Key wird benötigt, um die Wetterdaten abrufen zu können. 
!Der hier bereits hinterlegte Key funktioniert zwar, es können jedoch nur zeitlich begrenzt Wetterdaten abgerufen werden.
!Erstellung eines eigenen Keys unter http://openweathermap.org/appid

string owAppid='5e604af848492feb2e7e674c8f2431a7';


!Hier die ID der Wetterstation bzw. Stadt eitragen bzw. austauschen, von der die Wetterdaten abgerufen werden sollen.
!Eine Liste aller Stationen finden Sie unter http://bulk.openweathermap.org/sample/city.list.json.gz
!Die aktuell hinterlegte Station bzw. ID 6556765 gibt das Wetter für Berlin aus.
!Wenn Sie keine ID angeben UND in Ihrer Homematic unter "Einstellungen" > "Zeit-/Positionseinstellungen" unter dem Punkt "Positionsangabe"
!Ihre Koordinaten hinterlegt haben, können Sie von OpenWeather auch eine Wetterstation in Ihrer Nähe suchen lassen und deren Werte abrufen.
!Beispiele
!string owCityid='2950159';		Ruft die Wetterdaten für Berlin ab
!string owCityid='6556765';		Ruft die Wetterdaten für Pegnitz ab
!string owCityid='';			Ruft die Wetterdaten in Ihrer Nähe ab (wenn Positionsangaben in den Einstellungen hinterlegt wurden)
!string owCityid=false;			Ruft die Wetterdaten in Ihrer Nähe ab (wenn Positionsangaben in den Einstellungen hinterlegt wurden)

string owCityid='2950159';


!Optional: Im Folgenden die Namen der Systemvariablen ändern/vorgeben.
!Die abgerufenen Wetterdaten werden in mehreren Systemvariablen gespeichert und angezeigt (sie müssen vorab keine Variablen anlegen. Dies erledigt diese Script gegebenenfalls automatisch).
!Im Folgenden können Sie die Namen der Systemvariablen (so, wie Sie Ihnen in Ihrer Homematic später unter "Status und Bedienung" > "Systemvariable" angezeigt
!werden, ändern. Möchten Sie, dass ein bestimmter Messwert nicht angezeigt bzw. abgerufen wird, lassen Sie den Namen leer ''.
!Beispiele
!string svLuftdruck='ow Luftdruck';		Die Systemvariable für den Luftdruck soll "ow Lufdruck" heißen
!string svLuftdruck='Luftdr.';			Die Systemvariable für den Luftdruck soll "Luftdr." heißen
!string svLuftdruck='';					Es soll überhaupt kein Luftdruck angezeigt bzw. abgerufen werden
!string svLuftdruck=false;				Es soll überhaupt kein Luftdruck angezeigt bzw. abgerufen werden

string svAktualisierung='ow Letzte Aktualisierung';
string svTemperatur='ow Temperatur';
string svMinimalTemperatur='ow Temperatur (min.)';
string svMaximalTemperatur='ow Temperatur (max.)';
string svLuftfeuchtigkeit='ow Luftfeuchte (rel.)';
string svLuftdruck='ow Luftdruck';
string svWindGeschwindigkeit='ow Windgeschwindigkeit';
string svWindRichtung='ow Windrichtung';
string svWetterstation='ow Wetterstation';
string svSonnenaufgang='ow Sonnenaufgang';
string svSonnenuntergang='ow Sonnenuntergang';


!Optionale Experteneinstellungen: OpenWeather-Daten per CUxD abrufen
!Falls Sie in Ihrer Homematic die Software CUX-Daemon installiert haben, setzt dieses Script den wget-Command standardmäßig per
!CUxD "System-Devices" (28) bzw. Device CUxD.CUX2801001:1 ab. Hier gegebenenfalls den Namen des Devices nach dem Schema "CUxD.<Seriennummer>:1" ändern.
!Falls Sie nicht möchten, dass der wget-Gommand per CUxD sondern per system.Exec erfolgt, setzen Sie diese Variable auf false (string cuxCMDName=false;)

string cuxCMDName='CUxD.CUX2801001:1';


!Optionale Experteneinstellungen: OpenWeather-Daten bzw. Systemvariblen per CUxD Logit aufzeichnen
!Falls der CUX-Daemon installiert ist, werden die Messdaten der o.g. Systemvariablen dieses Scripts standardmäßig zusätzlich per CUxD LOGIT aufgezeichnet
!Falls Sie keine Aufzeichnng der Messdaten wünschen, ändern Sie diese Variable auf false (string cuxCMDName=false;)

boolean useLOGIT=true;


!Optionale Experteneinstellungen: OpenWeather-Daten in CUxD Thermostat-Device schreiben
!Falls der CUX-Daemon installiert ist und Sie ein "Universal Wrapper Device" (90) mit der Funktion "Thermostat" angelgt haben, kann dieses Script einige
!der abgerufenen Messwerte direkt in das Device schreiben (das ist der eigentliche Sinn dieses Scripts).
!Wichtig: Damit dies funktioniert, muss in den Einstellungen des Devices, im Kanal 1 die Option "WEATHER|USE_HMDATAPT" deaktiviert sein (nicht angehakt).
!Hier gegebenenfalls den Namen des Devices nach dem Schema "CUxD.<Seriennummer>:1" ändern.
!Falls Sie nicht möchten, dass Messwerte in das Device geschrieben werden, setzen Sie diese Variable auf false (string cuxWDSName=false;)

string cuxWDSName='CUxD.CUX9002001:1';





!************************************************************
!************************************************************
!BEGIN DES SCRIPTS
!************************************************************
!************************************************************

!Variablendeklaration
!***********************
!OpenWeather-Url mit Defaultwerte
string owLocation='&id=2950159';
string owUrl='http://api.openweathermap.org/data/2.5/weather?mode=xml&units=metric';
!CUxD/Exec und Rückgabe-Variablen (Programmablauf) mit Defaultwerte
boolean cuxCMD=false; boolean cuxWDS=false;string recXML;
!XML-Parser (Tagnamen)
string xmlStartTagName_Aktualisierung;string xmlEndTagName_Aktualisierung;
string xmlStartTagName_Temperatur;string xmlEndTagName_Temperatur;
string xmlStartTagName_Luftfeuchtigkeit;string xmlEndTagName_Luftfeuchtigkeit;
string xmlStartTagName_Luftdruck;string xmlEndTagName_Luftdruck;
string xmlStartTagName_Wind;string xmlEndTagName_Wind;
string xmlStartTagName_Geschwindigkeit;string xmlEndTagName_Geschwindigkeit;
string xmlStartTagName_Windrichtung;string xmlEndTagName_Windrichtung;
string xmlStartTagName_Stadt;string xmlEndTagName_Stadt;
string xmlStartTagName_Sonnenzeit;string xmlEndTagName_Sonnenzeit;
!XML-Parser (Programmablauf)
integer xmlStartTagLenght;
integer xmlTagStart;integer xmlTagLength;
integer xmlAttributeStart;integer xmlAttributeLength;
string xmlTagContent;
string xmlAttributeValue;
!Zurückgemeldete und aus der XML extrahierte Werte von OpenWeather
real owTemperatur;real owMinimalTemperatur;real owMaximalTemperatur;
real owLuftfeuchtigkeit;
real owLuftdruck;
real owWindGeschwindigkeit;real owGradzahl;string owWindRichtung;
string owWetterstation;
string owAktualisierung;
string owSonnenaufgang;string owSonnenuntergang;
!Objekte für Systemvariablen (Programmablauf)
object svObject;
object svObjectlist;
!Objekte für Devices (Programmablauf)
string dvObjectID;
object dvObject;
object dvObjectlist;
!Generische Variablen (Mehrfachverwendung)
string genString1;string genString2;string genString3;
time genTime1;
integer genInteger1;integer genInteger2;
real genReal1;

!Url zum Abruf des XML-Strings zusammen sezten
!****************************************************
if(owCityid){
	owLocation='&id='#owCityid;
} else {
	if(system.Longitude()&&system.Latitude())
	{
		owLocation='&lat='#system.Latitude()#'&lon='#system.Longitude();
	}
}
owUrl = owUrl#'&APPID='#owAppid#owLocation;

!Prüfen, ob CUX-Daemon Devices vorhanden sind
!***************************************************
if(dom.GetObject(cuxCMDName#'.CMD_SETS')){cuxCMD = true;}
if(dom.GetObject(cuxWDSName#'.SET_TEMPERATURE')){cuxWDS=true;}

!wget ausführen
!*****************
if(cuxCMD)
{
	!Website via CUxD und wget aufrufen.
	dom.GetObject(cuxCMDName#'.CMD_SETS').State("wget -q -O - '"#owUrl#"'");
	dom.GetObject(cuxCMDName#'.CMD_QUERY_RET').State(1);
	recXML = dom.GetObject(cuxCMDName#'.CMD_RETS').State();
} else {
	!Fallback: Website via system.Exec und wget aufrufen
	system.Exec("wget -q -O - '"#owUrl#"'", &recXML, &genString1); 
}

!Pruefen, ob XML-String geholt wurde, ansonsten abbrechen
!****************************************************************
if(!recXML){quit;}






!Tag-Namen-Suche im geholten XML-String vorbereiten
!*********************************************************
!Je nachdem, ob die Daten via CUxD oder Exex bezogen wurden, haben die XML-Tags ein anderes Format.
!Exex liefert einen XML-String mit eckigen Klammern nach dem Schema <tag></tag> oder <tag/>
!CUxD enternt eckige Klammern und liefert eine String nach dem Schema "tag /tag"
if(cuxCMD)
{
  !Suchstrings für XML-Tags von CUxD festlegen
  xmlStartTagName_Aktualisierung = 'lastupdate ';
  xmlEndTagName_Aktualisierung = '  /lastupdate';
  xmlStartTagName_Temperatur = 'temperature ';
  xmlEndTagName_Temperatur = '  /temperature';
  xmlStartTagName_Luftfeuchtigkeit = 'humidity ';
  xmlEndTagName_Luftfeuchtigkeit = '  /humidity';
  xmlStartTagName_Luftdruck = 'pressure ';
  xmlEndTagName_Luftdruck = '  /pressure';
  xmlStartTagName_Wind = 'wind ';
  xmlEndTagName_Wind = '  /wind';
  xmlStartTagName_Geschwindigkeit = 'speed ';
  xmlEndTagName_Geschwindigkeit = '  /speed';
  xmlStartTagName_Windrichtung = 'direction ';
  xmlEndTagName_Windrichtung = '  /direction';
  xmlStartTagName_Stadt = 'city ';
  xmlEndTagName_Stadt = '  /city';
  xmlStartTagName_Sonnenzeit = 'sun ';
  xmlEndTagName_Sonnenzeit = '  /sun';
} else {
  !Suchstrings für XML-Tags von Exec festlegen
  xmlStartTagName_Aktualisierung = '<lastupdate ';
  xmlEndTagName_Aktualisierung = '>';
  xmlStartTagName_Temperatur = '<temperature ';
  xmlEndTagName_Temperatur = '>';
  xmlStartTagName_Luftfeuchtigkeit = '<humidity ';
  xmlEndTagName_Luftfeuchtigkeit = '>';
  xmlStartTagName_Luftdruck = '<pressure ';
  xmlEndTagName_Luftdruck = '>';
  xmlStartTagName_Wind = '<wind>';
  xmlEndTagName_Wind = '</wind>';
  xmlStartTagName_Geschwindigkeit = '<speed ';
  xmlEndTagName_Geschwindigkeit = '>';
  xmlStartTagName_Windrichtung = '<direction ';
  xmlEndTagName_Windrichtung = '>';
  xmlStartTagName_Stadt = '<city ';
  xmlEndTagName_Stadt = '</city>';
  xmlStartTagName_Sonnenzeit = '<sun ';
  xmlEndTagName_Sonnenzeit = '>';
}

!Geholten XML-String parsen
!******************************

!Parser für svAktualisierung
if(svAktualisierung)
{
	xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;xmlTagContent='';
	xmlStartTagLenght = xmlStartTagName_Aktualisierung.Length();
	xmlTagStart = recXML.Find(xmlStartTagName_Aktualisierung);
	if (xmlTagStart>=0) 
	{
		xmlTagContent = recXML.Substr(xmlTagStart+xmlStartTagLenght); 
		xmlTagLength = xmlTagContent.Find(xmlEndTagName_Aktualisierung);
		if(xmlTagLength>0)
		{
			xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
		
			!Datenabruf-Attribut auslesen
			xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
			xmlAttributeStart=xmlTagContent.Find('value="');
			if (xmlAttributeStart>=0) 
			{
				xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+7);
				xmlAttributeLength = xmlAttributeValue.Find('"');
				xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
				owAktualisierung = xmlAttributeValue.ToString();
			}
		}
	}
}



!Parser für svTemperatur, svMinimalTemperatur, svMaximalTemperatur
if(svTemperatur)
{
	xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;xmlTagContent='';
	xmlStartTagLenght = xmlStartTagName_Temperatur.Length();
	xmlTagStart = recXML.Find(xmlStartTagName_Temperatur);
	if (xmlTagStart>=0) 
	{
		xmlTagContent = recXML.Substr(xmlTagStart+xmlStartTagLenght); 
		xmlTagLength = xmlTagContent.Find(xmlEndTagName_Temperatur);
		if(xmlTagLength>0)
		{
			xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
		
			!Temperatur-Attribut auslesen
			xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
			xmlAttributeStart=xmlTagContent.Find('value="');
			if (xmlAttributeStart>=0) 
			{
				xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+7);
				xmlAttributeLength = xmlAttributeValue.Find('"');
				xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
				owTemperatur = xmlAttributeValue.ToFloat();
			}	
		
			!MinimalTemperatur-Attribut auslesen
			xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
			xmlAttributeStart=xmlTagContent.Find('min="');
			if (xmlAttributeStart>=0) 
			{
				xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+5);
				xmlAttributeLength = xmlAttributeValue.Find('"');
				xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
				owMinimalTemperatur = xmlAttributeValue.ToFloat();
			}	
		
			!MaximalTemperatur-Attribut auslesen
			xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
			xmlAttributeStart=xmlTagContent.Find('max="');
			if (xmlAttributeStart>=0) 
			{
				xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+5);
				xmlAttributeLength = xmlAttributeValue.Find('"');
				xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
				owMaximalTemperatur = xmlAttributeValue.ToFloat();
			}
		
		}
	}
}



!Parser für svLuftfeuchtigkeit
if(svLuftfeuchtigkeit)
{
	xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;xmlTagContent='';
	xmlStartTagLenght = xmlStartTagName_Luftfeuchtigkeit.Length();
	xmlTagStart = recXML.Find(xmlStartTagName_Luftfeuchtigkeit);
	if (xmlTagStart>=0) 
	{
		xmlTagContent = recXML.Substr(xmlTagStart+xmlStartTagLenght); 
		xmlTagLength = xmlTagContent.Find(xmlEndTagName_Luftfeuchtigkeit);
		if(xmlTagLength>0)
		{
			xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
		
			!Luftfeuchtigkeits-Attribut auslesen
			xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
			xmlAttributeStart=xmlTagContent.Find('value="');
			if (xmlAttributeStart>=0) 
			{
				xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+7);
				xmlAttributeLength = xmlAttributeValue.Find('"');
				xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
				owLuftfeuchtigkeit = xmlAttributeValue.ToFloat();
			}	
	
		}
	}
}


!Parser für svLuftdruck
if(svLuftdruck)
{
	xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;xmlTagContent='';
	xmlStartTagLenght = xmlStartTagName_Luftdruck.Length();
	xmlTagStart = recXML.Find(xmlStartTagName_Luftdruck);
	if (xmlTagStart>=0) 
	{
		xmlTagContent = recXML.Substr(xmlTagStart+xmlStartTagLenght); 
		xmlTagLength = xmlTagContent.Find(xmlEndTagName_Luftdruck);
		if(xmlTagLength>0)
		{
			xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
		
			!Luftdruck-Attribut auslesen
			xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
			xmlAttributeStart=xmlTagContent.Find('value="');
			if (xmlAttributeStart>=0) 
			{
				xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+7);
				xmlAttributeLength = xmlAttributeValue.Find('"');
				xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
				owLuftdruck = xmlAttributeValue.ToFloat();
			}	
	
		}
	}
}


!Parser für owWindGeschwindigkeit
if(svWindGeschwindigkeit)
{
	xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;xmlTagContent='';
	xmlStartTagLenght = xmlStartTagName_Wind.Length();
	xmlTagStart = recXML.Find(xmlStartTagName_Wind);
	if (xmlTagStart>=0) 
	{
		xmlTagContent = recXML.Substr(xmlTagStart+xmlStartTagLenght); 
		xmlTagLength = xmlTagContent.Find(xmlEndTagName_Wind);
		if(xmlTagLength>0)
		{
			xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
			
			!Sub-Parser Geschwindigkeit
			xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;
			xmlStartTagLenght = xmlStartTagName_Geschwindigkeit.Length();
			xmlTagStart = xmlTagContent.Find(xmlStartTagName_Geschwindigkeit);
			if (xmlTagStart>=0) 
			{
				xmlTagContent = xmlTagContent.Substr(xmlTagStart+xmlStartTagLenght); 
				xmlTagLength = xmlTagContent.Find(xmlEndTagName_Geschwindigkeit);
				if(xmlTagLength>0)
				{
					xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
		
					!Geschwindigkeit-Attribut auslesen
					xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
					xmlAttributeStart=xmlTagContent.Find('value="');
					if (xmlAttributeStart>=0) 
					{
						xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+7);
						xmlAttributeLength = xmlAttributeValue.Find('"');
						xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
						owWindGeschwindigkeit = xmlAttributeValue.ToFloat();
					}	
	
				}
			}
			
		}
	}
}



!Parser für owGradzahl, owWindRichtung
if(svWindRichtung)
{
	xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;xmlTagContent='';
	xmlStartTagLenght = xmlStartTagName_Wind.Length();
	xmlTagStart = recXML.Find(xmlStartTagName_Wind);
	if (xmlTagStart>=0) 
	{
		xmlTagContent = recXML.Substr(xmlTagStart+xmlStartTagLenght); 
		xmlTagLength = xmlTagContent.Find(xmlEndTagName_Wind);
		if(xmlTagLength>0)
		{
			xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
			
			!Sub-Parser Windrichtng
			xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;
			xmlStartTagLenght = xmlStartTagName_Windrichtung.Length();
			xmlTagStart = xmlTagContent.Find(xmlStartTagName_Windrichtung);
			if (xmlTagStart>=0) 
			{
				xmlTagContent = xmlTagContent.Substr(xmlTagStart+xmlStartTagLenght); 
				xmlTagLength = xmlTagContent.Find(xmlEndTagName_Windrichtung);
				if(xmlTagLength>0)
				{
					xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
		
					!Gradzahl-Attribut auslesen
					xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
					xmlAttributeStart=xmlTagContent.Find('value="');
					if (xmlAttributeStart>=0) 
					{
						xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+7);
						xmlAttributeLength = xmlAttributeValue.Find('"');
						xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
						owGradzahl = xmlAttributeValue.ToInteger();
					}	
					
					!Himmelsrichtung-Attribut auslesen
					xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
					xmlAttributeStart=xmlTagContent.Find('code="');
					if (xmlAttributeStart>=0) 
					{
						xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+6);
						xmlAttributeLength = xmlAttributeValue.Find('"');
						xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
						owWindRichtung = xmlAttributeValue.ToString();
					}	
	
				}
			}
		}
	}
}



!Parser für owWetterstation
if(svWetterstation)
{
	xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;xmlTagContent='';
	xmlStartTagLenght = xmlStartTagName_Stadt.Length();
	xmlTagStart = recXML.Find(xmlStartTagName_Stadt);
	if (xmlTagStart>=0) 
	{
		xmlTagContent = recXML.Substr(xmlTagStart+xmlStartTagLenght); 
		xmlTagLength = xmlTagContent.Find(xmlEndTagName_Stadt);
		if(xmlTagLength>0)
		{
			xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
			
			!Stadtname-Attribut auslesen
			xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
			xmlAttributeStart=xmlTagContent.Find('name="');
			if (xmlAttributeStart>=0) 
			{
				xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+6);
				xmlAttributeLength = xmlAttributeValue.Find('"');
				xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
				owWetterstation = xmlAttributeValue.ToString();
			}	
			
			!Sub-Parser Sonnezeit
			xmlStartTagLenght=0;xmlTagStart=0;xmlTagLength=0;
			xmlStartTagLenght = xmlStartTagName_Sonnenzeit.Length();
			xmlTagStart = xmlTagContent.Find(xmlStartTagName_Sonnenzeit);
			if (xmlTagStart>=0) 
			{
				xmlTagContent = xmlTagContent.Substr(xmlTagStart+xmlStartTagLenght); 
				xmlTagLength = xmlTagContent.Find(xmlEndTagName_Sonnenzeit);
				if(xmlTagLength>0)
				{
					xmlTagContent = xmlTagContent.Substr(0,xmlTagLength);
		
					!Sonnenaufgang-Attribut auslesen
					xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
					xmlAttributeStart=xmlTagContent.Find('rise="');
					if (xmlAttributeStart>=0) 
					{
						xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+6);
						xmlAttributeLength = xmlAttributeValue.Find('"');
						xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
						owSonnenaufgang = xmlAttributeValue.ToString();
					}	
					
					!Sonnenuntergang-Attribut auslesen
					xmlAttributeStart=0;xmlAttributeLength=0;xmlAttributeValue='';
					xmlAttributeStart=xmlTagContent.Find('set="');
					if (xmlAttributeStart>=0) 
					{
						xmlAttributeValue = xmlTagContent.Substr(xmlAttributeStart+5);
						xmlAttributeLength = xmlAttributeValue.Find('"');
						xmlAttributeValue = xmlAttributeValue.Substr(0,xmlAttributeLength);
						owSonnenuntergang = xmlAttributeValue.ToString();
					}	
	
				}
			}
		}
	}
}






!Ermittelte Werte in Systemvariable schreiben
!**************************************************
!Wenn (noch) keine Systemvariable(n) vorhanden, diese anlegen.
!Code zum anlegen von Variablen abgeleitet von Esche's IT-Blog https://www.blogging-it.com/code-snippet-homematic-systemvariablen-ueber-ein-script-automatisch-erzeugen/programmierung/homematic-script.html

!Schreiben von svAktualisierung
if(svAktualisierung)
{
	!String bzw. Uhrzeit umformatieren
	genString1='';genTime1=null;genString2='';
	genString1 = owAktualisierung.Substr(0,10)#' '#owAktualisierung.Substr(11);
	genTime1 = genString1.ToTime();
	genString2 = genTime1.Format("%d.%m.%Y %H:%M"#" Uhr");
	svObject = dom.GetObject(svAktualisierung);
	!Wenn noch keine Systemvarible vorhanden, diese anlegen
	if (!svObject)
	{   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svAktualisierung);   
	    svObject.ValueType(ivtString);
	    svObject.ValueSubType(istChar8859);
	    svObject.DPInfo('OpenWeatherMap - Aktualisierung');
	    svObject.ValueUnit('');
	    svObject.State(genString2);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(genString2);
	}
	!Wenn CUxD-CMD-Device vorhanden und useLOGIT, dann Werte via CUxD loggen
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svAktualisierung#';'#genTime1);}
}



!Schreiben von svSonnenaufgang
if(svSonnenaufgang)
{
	genString1='';genTime1=null;genString2='';
	genString1 = owSonnenaufgang.Substr(0,10)#' '#owSonnenaufgang.Substr(11);
	genTime1 = genString1.ToTime();
	genString2 = genTime1.Format("%d.%m.%Y %H:%M"#" Uhr");
	svObject = dom.GetObject(svSonnenaufgang);
	if (!svObject)
	{   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svSonnenaufgang);   
	    svObject.ValueType(ivtString);
	    svObject.ValueSubType(istChar8859);
	    svObject.DPInfo('OpenWeatherMap - Sonnenaufgang');
	    svObject.ValueUnit('');
	    svObject.State(genString2);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(genString2);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svSonnenaufgang#';'#genTime1);}
}



!Schreiben von svSonnenuntergang
if(svSonnenuntergang)
{
	genString1='';genTime1=null;genString2='';
	genString1 = owSonnenuntergang.Substr(0,10)#' '#owSonnenuntergang.Substr(11);
	genTime1 = genString1.ToTime();
	genString2 = genTime1.Format("%d.%m.%Y %H:%M"#" Uhr");
	svObject = dom.GetObject(svSonnenuntergang);
	if (!svObject)
	{   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svSonnenuntergang);   
	    svObject.ValueType(ivtString);
	    svObject.ValueSubType(istChar8859);
	    svObject.DPInfo('OpenWeatherMap - Sonnenuntergang');
	    svObject.ValueUnit('');
	    svObject.State(genString2);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(genString2);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svSonnenuntergang#';'#genTime1);}
}



!Schreiben von svWetterstation
if(svWetterstation)
{
	genString1='';genString2='';genString3='';genInteger1=0;genInteger2=0;
	genInteger1=owWetterstation.Length();
	foreach(genInteger2,genInteger1)
	{
		genString1=owWetterstation.Substr(genInteger2-1,1);
		if(genString1=='Ã')
		{
			genString2=owWetterstation.Substr(genInteger2,1);
			if(genString2=='¼'){genString1='ü';genInteger2=genInteger2+1;}
			if(genString2=='¶'){genString1='ö';genInteger2=genInteger2+1;}
			if(genString2=='¤'){genString1='ä';genInteger2=genInteger2+1;}
		}
		genString3=genString3#genString1;
	}
	
	svObject = dom.GetObject(svWetterstation);
	if (!svObject)
	{   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svWetterstation);   
	    svObject.ValueType(ivtString);
	    svObject.ValueSubType(istChar8859);
	    svObject.DPInfo('OpenWeatherMap - Wetterstation');
	    svObject.ValueUnit('');
	    svObject.State(genString3);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(genString3);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svWetterstation#';'#genString3);}
}



!Schreiben von svWindgeschwindigkeit
if(svWindGeschwindigkeit)
{
	svObject = dom.GetObject(svWindGeschwindigkeit);
	if (!svObject){   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svWindGeschwindigkeit);   
	    svObject.ValueType(ivtFloat);
	    svObject.ValueSubType(istGeneric);
	    svObject.DPInfo("OpenWeatherMap - Windgeschwindigkeit");
	    svObject.ValueUnit("m/s");
	    svObject.ValueMin(0.0000);
	    svObject.ValueMax(500.0000);
	    svObject.State(owWindGeschwindigkeit);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(owWindGeschwindigkeit);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svWindGeschwindigkeit#';'#owWindGeschwindigkeit);}
}

	

!Schreiben von svLuftdruck
if(svLuftdruck)
{
	svObject = dom.GetObject(svLuftdruck);
	if (!svObject){   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svLuftdruck);   
	    svObject.ValueType(ivtFloat);
	    svObject.ValueSubType(istGeneric);
	    svObject.DPInfo("OpenWeatherMap - Luftdruck");
	    svObject.ValueUnit("hPa");
	    svObject.ValueMin(500.0000);
	    svObject.ValueMax(1100.0000);
	    svObject.State(owLuftdruck);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(owLuftdruck);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svLuftdruck#';'#owLuftdruck);}
}

	

!Schreiben von svTemperatur
if(svTemperatur)
{
	svObject = dom.GetObject(svTemperatur);
	if (!svObject){   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svTemperatur);   
	    svObject.ValueType(ivtFloat);
	    svObject.ValueSubType(istGeneric);
	    svObject.DPInfo("OpenWeatherMap - Temperatur");
	    svObject.ValueUnit("°C");
	    svObject.ValueMin(-50.0000);
	    svObject.ValueMax(50.0000);
	    svObject.State(owTemperatur);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(owTemperatur);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svTemperatur#';'#owTemperatur);}
	if(cuxWDS){dom.GetObject(cuxWDSName#'.SET_TEMPERATURE').State(owTemperatur);}
}



!Schreiben von svMinimalTemperatur
if(svMinimalTemperatur)
{
	svObject = dom.GetObject(svMinimalTemperatur);
	if (!svObject){   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svMinimalTemperatur);   
	    svObject.ValueType(ivtFloat);
	    svObject.ValueSubType(istGeneric);
	    svObject.DPInfo("OpenWeatherMap - Temperatur (min.)");
	    svObject.ValueUnit("°C");
	    svObject.ValueMin(-50.0000);
	    svObject.ValueMax(50.0000);
	    svObject.State(owMinimalTemperatur);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(owMinimalTemperatur);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svMinimalTemperatur#';'#owMinimalTemperatur);}
}



!Schreiben von svMaximalTemperatur
if(svMaximalTemperatur)
{
	svObject = dom.GetObject(svMaximalTemperatur);
	if (!svObject){   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svMaximalTemperatur);   
	    svObject.ValueType(ivtFloat);
	    svObject.ValueSubType(istGeneric);
	    svObject.DPInfo("OpenWeatherMap - Temperatur (max.)");
	    svObject.ValueUnit("°C");
	    svObject.ValueMin(-50.0000);
	    svObject.ValueMax(50.0000);
	    svObject.State(owMaximalTemperatur);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(owMaximalTemperatur);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svMaximalTemperatur#';'#owMaximalTemperatur);}
}



!Schreiben von svLuffeuchtigkeit
if(svLuftfeuchtigkeit)
{
	svObject = dom.GetObject(svLuftfeuchtigkeit);
	if (!svObject){   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svLuftfeuchtigkeit);   
	    svObject.ValueType(ivtFloat);
	    svObject.ValueSubType(istGeneric);
	    svObject.DPInfo("OpenWeatherMap - Luftfeuchtigkeit");
	    svObject.ValueUnit("%");
	    svObject.ValueMin(0.0000);
	    svObject.ValueMax(100.0000);
	    svObject.State(owLuftfeuchtigkeit);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(owLuftfeuchtigkeit);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svLuftfeuchtigkeit#';'#owLuftfeuchtigkeit);}
	if(cuxWDS){dom.GetObject(cuxWDSName#'.SET_HUMIDITY').State(owLuftfeuchtigkeit);}
}



!Schreiben von svWindrichtung
if(svWindRichtung)
{
	!Englische Windrichtungsangaben übersetzen (z.B. N-W-E in Nord-West-Ost)
	genString1='';genString2='';genString3='';genInteger1=0;
	genString1 = owWindRichtung;
	foreach(genInteger1,genString1.Length())
	{
		genString2=genString1.Substr(genInteger1-1,1);
		if(genString2=='E'){genString3=genString3#'Ost-';}
		if(genString2=='S'){genString3=genString3#'Süd-';}
		if(genString2=='W'){genString3=genString3#'West-';}
		if(genString2=='N'){genString3=genString3#'Nord-';}
	}
	genString1=genString3.Substr(0,genString3.Length()-1);
	genString2=owGradzahl.ToString()#'° '#genString1;
	svObject = dom.GetObject(svWindRichtung);
	if (!svObject)
	{   
	    svObjectlist = dom.GetObject(ID_SYSTEM_VARIABLES);
	    svObject = dom.CreateObject(OT_VARDP);
	    svObjectlist.Add(svObject.ID());
	    svObject.Name(svWindRichtung);   
	    svObject.ValueType(ivtString);
	    svObject.ValueSubType(istChar8859);
	    svObject.DPInfo('OpenWeatherMap - Windrichtung');
	    svObject.ValueUnit('');
	    svObject.State(genString2);
	    svObject.Internal(false);
	    svObject.Visible(true);
	    dom.RTUpdate(true);
	} else {
		svObject.State(genString2);
	}
	if((cuxCMD)&&(useLOGIT)){dom.GetObject(cuxCMDName#'.LOGIT').State(svWindRichtung#';'#genString2);}
}	
Zuletzt geändert von OffroadXC am 10.03.2017, 12:30, insgesamt 2-mal geändert.

tb59427
Beiträge: 5
Registriert: 07.02.2017, 18:29

Re: HM-Script für virtuelle Wetterstation

Beitrag von tb59427 » 27.02.2017, 13:51

Tolles Skript. Vielen Dank - ist auch eine schöne Lehrstunde für mich, HM Skript besser kennenzulernen.

Sämtliche Zeiten in dem XML Reply scheinen UTC Zeiten zu sein. Gibt es in HM Skript einen _einfachen_ Weg das in Local Zeiten umzurechnen?

Gruß
Torsten

tb59427
Beiträge: 5
Registriert: 07.02.2017, 18:29

Re: HM-Script für virtuelle Wetterstation

Beitrag von tb59427 » 27.02.2017, 14:26

Die Zeile

owWindGeschwindigkeit = xmlAttributeValue.ToFloat();

muß (zumindest für meinen Standort) in

owWindGeschwindigkeit = xmlAttributeValue.ToFloat()*3600/1000;

geändert werden. OpenweatherMap liefert Windgeschwindigkeit in m/s - Anzeige in km/h (oder kts) ist eigentlich üblicher.

Gruß
Torsten

alchy
Beiträge: 7714
Registriert: 24.02.2011, 01:34

Re: HM-Script für virtuelle Wetterstation

Beitrag von alchy » 27.02.2017, 15:15

tb59427 hat geschrieben: Sämtliche Zeiten in dem XML Reply scheinen UTC Zeiten zu sein. Gibt es in HM Skript einen _einfachen_ Weg das in Local Zeiten umzurechnen?
>> H I E R << als Anfang.

Alchy

.................... Full
Ignoranz ist die Summe aller Maßnahmen die man ergreift, um bestehende Tatsachen nicht sehen zu müssen.

© Sandra Pulsfort (*1974)

Lies bitte die Logik von WebUI Programmen und die Tipps und Tricks für Anfänger.

Wichtig auch CUxD ersetzt System.exec. Die HM Script Doku (Downloadart Skripte) hilft auch weiter.
Zum Testen von Scripten den >> HomeMatic Script Executor << von Anli benutzen.

Chemieka
Beiträge: 277
Registriert: 03.01.2017, 17:39

Re: HM-Script für virtuelle Wetterstation

Beitrag von Chemieka » 27.02.2017, 17:17

Ich hatte ja das Skript gleich zu beginn angelegt. Bei mir kommt es zu aussetzern. So ist das letzte Update von heute Früh. Hat das noch jemand? Gehe ich nochmal ins Programm rein und drücke OK geht's wieder ein paar Stunden.
PI3 mit RaspberryMatic; PI3 mit IOBroker; Samsung Tab A gerootet mit Mediola Visualisierung; Harmony Hub; Philips Hue; Zwei IP Cams; Zwei Leseköpfe an den Stromzählern zur Darstellung des Stromverbrauches. CUL433 für Intertechno und Somfy RTS

Chombo01
Beiträge: 3
Registriert: 03.01.2017, 16:22

Re: HM-Script für virtuelle Wetterstation

Beitrag von Chombo01 » 02.03.2017, 13:07

Ja bei mir ist es genau so, zuerst dachte ich das es zu oft ausgeführt wird aber alle 3 Stunden sollte kein Problem sein.
Wenn ich es Manuel ausführe geht es immer.

Gesendet von meinem PLK-L01 mit Tapatalk

OffroadXC
Beiträge: 13
Registriert: 01.04.2016, 19:36

Re: HM-Script für virtuelle Wetterstation

Beitrag von OffroadXC » 02.03.2017, 20:40

Die Aktualisierung passiert bei mir problemlos. Ich habe 2h bei mir eingestellt. Es können ja bis zu 60 Abrufe pro Minute getätigt werden. Die Aktualisierung der Wetterdaten von OpenWetherMap werden aller 2 Stunden in der kostenlosen Variante bereitgestellt.
Was ich jedoch festgestellt habe, die Sonnenaufgangs- u. Sonnenuntergangszeit weicht jeweils um eine Stunde von der richtigen Zeit ab - es wird die UTC-Zeit in der XML-Datei gesendet. Diese Zeit müsste also noch an die Ortszeit angepasst werden zB.UTC +1h Dabei finde ich, dass von OpenWetherMap normal die richtige Zeit gesendet gleich gesendet werden sollte, da ich ja auch einen speziellen Ort anfrage.

Beezy
Beiträge: 36
Registriert: 12.03.2016, 23:18
Wohnort: Hermsdorf

Re: HM-Script für virtuelle Wetterstation

Beitrag von Beezy » 11.03.2017, 00:12

tb59427 hat geschrieben:Die Zeile

owWindGeschwindigkeit = xmlAttributeValue.ToFloat();

muß (zumindest für meinen Standort) in

owWindGeschwindigkeit = xmlAttributeValue.ToFloat()*3600/1000;

geändert werden. OpenweatherMap liefert Windgeschwindigkeit in m/s - Anzeige in km/h (oder kts) ist eigentlich üblicher.

Gruß
Torsten
Wenn ich es so mache wie du es schreibst rechnet er nur "*3"
Leichter wäre es sowieso statt "*3600/1000" einfach "*3,6" zu rechnen. Allerdings funktioniert es nur wenn man statt dem Komma ein Punkt setzt.
So funktioniert es bei mir richtig:

owWindGeschwindigkeit = xmlAttributeValue.ToFloat()*3.6;
Stand 2018:
Homematic auf RaspberryMatic: 35 Geräte, 56 Programme, 11 Direkte Verknüpfungen und 56 Systemvariablen
ioBroker auf Rock64
div. Xiaomi Mi Home Produkte
Yeelight
Mi Robot 1. Gen

Antworten

Zurück zu „Projektvorstellungen“