Hi Martin,
ich habe ebenfalls diese Disconnects. Diese kommen fast jede Minute.
2013.05.13 15:25:05 1: 192.168.1.170:1000 reappeared (01_LANInterface)
2013.05.13 15:25:00 1: 192.168.1.170:1000 disconnected, waiting to reappear
2013.05.13 15:23:07 1: 192.168.1.170:1000 reappeared (01_LANInterface)
2013.05.13 15:23:02 1: 192.168.1.170:1000 disconnected, waiting to reappear
2013.05.13 15:22:05 1: 192.168.1.170:1000 reappeared (01_LANInterface)
2013.05.13 15:22:00 1: 192.168.1.170:1000 disconnected, waiting to reappear
2013.05.13 15:21:05 1: 192.168.1.170:1000 reappeared (01_LANInterface)
2013.05.13 15:21:00 1: 192.168.1.170:1000 disconnected, waiting to reappear
2013.05.13 15:19:35 1: 192.168.1.170:1000 reappeared (01_LANInterface)
2013.05.13 15:19:30 1: 192.168.1.170:1000 disconnected, waiting to reappear
2013.05.13 15:18:09 1: 192.168.1.170:1000 reappeared (01_LANInterface)
2013.05.13 15:18:04 1: 192.168.1.170:1000 disconnected, waiting to reappear
Ich habe auch bereits herausgefunden an was es liegt. Und zwar habe ich mit Hilfe von UliM diese Abfrage von Werten aus einer XML eingebaut. Hiermit wird zum Beispiel minütlich die Aussentemperatur abgefragt:
define html_aufruf_at at +*00:01:00 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi");;\
foreach (@werte) {\
if( $_ =~ m"<VALUE>(.*)<\/VALUE>") {\
my $wert = $1;;\
fhem("set AT $wert");;\
}\
}\
}
define AT dummy
attr AT alias Aussentemperatur
Diesen ganzen Code gibt es natürlich nicht nur einmal sondern mehrmals für unterschiedliche Werte (Vorlauftemperatur, Rücklauftemperatur, usw. usf.). Kommentiere ich diese aus, sind die Disconnects weg.
Jetzt weiß ich nicht so recht weiter und vermute das Netzwerk ist dann überlastet oder was auch immer. Wobei ich nicht ganz verstehen kann was das eine hier mit dem anderen zu tun hat. Benötigst Du für eine genaue Analyse noch mehr Infos? Wenn ja, welche? Oder liegt es nur an dem Code oben? Müsste man da etwas ändern?
Danke
Gruß
TinoB
Hallo TinoB,
evtl ist nicht das Netzwerk tot sondern der FHEM prozess.
Man koennte ausmessen, wie lange einer deiner Aufrufe dauert. Wenn es mehrere sind muss man die Addieren. Dann hat man die Zeit, die dieser Vorgang benötigt und somit alles andere in FHEM blockiert.
Was kommt den so alles aus deinem CGI zurück? Ist es sinnvoll, das file mit match zu durchsuchen oder kann man das schneller? mit grep evtl?
Da steht doch nur ein wert drin - du kannst in jeden Fall mit "last" nach dem finden abbrechen.
Evtl kannst du auch alle Abfragen - du hast mehrere Fühler - in ein at zusammenfassen.
Kurzum - erst performance analyse, dann tuning.
Wenn es daran liegt wie lange dein device zum Antworten braucht sollte man den Prozess auslagern. Das ist auf User-level etwas komplexer (jedenfalls habe ich noch nicht nachgedacht darüber).
Fange einmal an mit "gettimeofday()" die Zeiten zu messen
my $start = gettimeofday();
aktionen
my $duration = gettimeofday()-$start;
Gruss
Martin
Hallo Martin,
ok, dies habe ich eingefügt:
define html_aufruf_at at +*00:01:00 {\
my $start = gettimeofday();;\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|20");;\
foreach (@werte) {\
if( $_ =~ m"<VALUE>(.*)<\/VALUE>") {\
my $wert = $1;;\
fhem("set AT $wert");;\
}\
}\
my $duration = gettimeofday()-$start;;\
fhem("set 1_Time_at $duration");;\
}
Herausgekommen sind da Zeiten von ca. 0,7 Sekunden. Das ganze natürlich mal 11 Werte. Auch wenn die Abfragen alle nicht immer zeitgleich stattfinden ist das schon eine Menge oder? Ich habe da nicht so die Erfahrung.
Zum Test habe ich nun die Abfragezeiten in dem at zeitversetzt von 5 Sekunden. Also zum Beispiel Wert 1 mit 25 Sekunden, Wert 2 auf 30 Sekunden usw. usf. Und siehe da, es wurde kein Disconnect gemeldet.
Jetzt könnte ich daraus Schlußfolgern, dass ich die Abfrage optimieren könnte. Sehe ich das richtig?
ZitatEvtl kannst du auch alle Abfragen - du hast mehrere Fühler - in ein at zusammenfassen.
Genau dies könnte des Rätsels Lösung sein.
Es kann die Abfrage aller Werte über die CGI erfolgen. Als Ergebnis würde ich dann zum Beispiel folgende XML erhalten:
</WEB>
</PCO>
</ANALOG>
</VARIABLE>
...........
<VARIABLE>
</VARIABLE>
<VALUE>-999.9</VALUE>
<INDEX>4</INDEX>
<VARIABLE>
</VARIABLE>
<VALUE>37.8</VALUE>
<INDEX>3</INDEX>
<VARIABLE>
</VARIABLE>
<VALUE>22.2</VALUE>
<INDEX>2</INDEX>
<VARIABLE>
</VARIABLE>
<VALUE>17.5</VALUE>
<INDEX>1</INDEX>
<VARIABLE>
<ANALOG>
<PCO>
<WEB>
Bisher wird ja nur jeweils 1 Index abgefragt. Somit müsste die Schleife erweitert werden und der Index + den jeweiligen Value abgefragt und in die Logdatei geschrieben werden.
Allerdings bekomme ich das nicht selbst hin. Hast Du hier eine Idee, was in der Schleife geändert werden muss?
Danke
TinoB
Hallo TinoB,
0.7sec ist schon etwas - wenn es nicht koordiniert ist und mal 11 sind dies 7,7sec delay. Fuer mich ist dies nicht tragbar - wir wollen doch unser licht in Echtzeit anschalten. HMLAN kann bei einer Verzoegerung von 5 sec disconnected.
Es gibt 2 vorgehensweisen
a) optimieren
b) entkoppeln
Vorerst einmal optimieren - entkoppeln ist besser aber deutlich komplexer.
Wenn ich mir den input ansehe kommen die passenden Werte "<VALUE>(.*)<\/VALUE>" mehrfach mit verschiedenen indizes - und alle werden nach AT geschrieben. Macht dass sinn? Oder willst du nur einen schreiben? Stehen bleibt der Letzte, also index 1.
Frage a) wer verzoegert: GetHttpFile oder die Suche und das Setzen?
schreiben einmal
my $start = gettimeofday();;\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|20");;\
my $duration = gettimeofday()-$start;;\
foreach (@werte) {\
.......
falls die Verzoegerung durch das get kommt ist es nicht notwendig (aber schoener...) die Auswertung zu tunen.
Du koenntest einen timer starten und alle 5 sec einen anderen Fuehler auslesen. Dann hast du immer noch 0.7sec delay alle 5 sec, aber keinen Burst mehr - alles kontrolliert eben.
Das ganze zu forken gibt es noch nicht mit User-Interface Unterstuetzung - dann waeren die Delays aber egal.
Gruss Martin
Hallo Martin,
ok ich muss zugeben ich verstehe teilweise nur Bahnhof ;-) aber das macht ja nix, ich will es lernen und verstehen.
Ich meine ich habe etwas falsch beschrieben. Diese 0,7 Sekunden kommen bei jeder Abfrage, egal wie viele Werte abgefragt werden. Mit dieser hier habe ich begonnen um die Aussentemperatur abzufragen:
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|1");;\
foreach (@werte) {\
if( $_ =~ m"<VALUE>(.*)<\/VALUE>") {\
my $wert = $1;;\
fhem("set AT $wert");;\
}\
}\
}
Von diesen Abfragen habe ich im Moment 11 am LaufenDabei werden immer nur die Abfrageindizes geändert. Hier zum Beispiel Index 2:
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|2|2");;\
oder Index 3:
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|3|3");;\
Dabei dauert jede Abfrage ca. 0,7 Sekunden und wie Du schreibst können dies dann ganz schnell mal 7,7 Sekunden werden.
Jetzt kann man aber auch mit dieser Abfrage mehrere Werte miteinmal erhalten.
Zum Beispiel mit Index 1-10:
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
Das heißt, es werden die Analogindizes 1 bis 10 abgefragt. Ich habe auch hier die Zeit aufgenommen wie von Dir vorgeschlagen. Und dabei spielt es keine Rolle ob die Indizes 1-10 oder 1-100 abgefragt werden. Es dauert immer ca. 0,7 Sekunden. Die Schlußfolgerung wäre, genau das was Du schreibst, das Tuning. Ich gehe davon aus, dass wenn die Werte immer einmal komplett abgefragt werden das Problem damit gelöst ist.
Nur, und das ist jetzt die Frage, wie mach ich das?
Man erhält mit der oben genannten Abfrage von Wert 1 bis XX diese XML zurück.
</WEB>
</PCO>
</ANALOG>
</VARIABLE>
....
....
<VARIABLE>
</VARIABLE>
<VALUE>-999.9</VALUE>
<INDEX>4</INDEX>
<VARIABLE>
</VARIABLE>
<VALUE>37.8</VALUE>
<INDEX>3</INDEX>
<VARIABLE>
</VARIABLE>
<VALUE>22.2</VALUE>
<INDEX>2</INDEX>
<VARIABLE>
</VARIABLE>
<VALUE>17.5</VALUE>
<INDEX>1</INDEX>
<VARIABLE>
<ANALOG>
<PCO>
<WEB>
Und es sollen nur bestimmte Indizes genutzt werden. Also z.B. in eine Logdatei geschrieben werden oder oder oder ..
Wie muss ich den bisherigen Code
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
foreach (@werte) {\
if( $_ =~ m"<VALUE>(.*)<\/VALUE>") {\
my $wert = $1;;\
fhem("set AT $wert");;\
}\
}\
}
ergänzen/anpassen, damit aus der Abfrage von 1 bis 10 nur die Werte von bestimmten Indizes geloggt werden?
Danke
Gruß
TinoB
Hi ToniB,
Zitatich verstehe teilweise nur Bahnhof
werde mich bemühen.
Jeden Wert einzeln abfragen sollte man in jeden Fall vermeiden - der Overhead ist, wie man sieht, erheblich im Internet, gerade bei nur einem Wert.
Wenn du nun alle 10 (oder 100) Werte in einem Zug holst kann man die auswerten. Nur weiss ich nicht, was sie Bedeuten oder was du damit machen willst. Voraussichtich haben die 10 jeder eine andere Bedeutung und sollen in eine andere Variable.
Die ausgabe deines web-device sendet erst den Wert und dann den Index - also muessen wir uns den Wert merken und auf den index warten. Wenn der Index kommt koennen wir ausgeben.
Hier etwas zum Spielen:
my $val;
foreach (@werte){
if($_ =~m"<INDEX>(.*)</INDEX>"){
Log 1, "found Idx:$1 Val:$val";
fhem("set AT$1 $val");
}
$val=$1 if($_ =~m"<VALUE>(.*)</VALUE>");
}
wir speichern den Wert in $val - sobald wir einen finden. Immer wenn ein "Index" kommt geben wir dann $val aus. Im Beispiel passiert es 2 mal: einmal als log und einmal als set in eine Dummy Variable. Du musst also vorher die AT definiert haben
define AT1 dummy
define AT2 dummy
.....
Alternativ - falls die Werte eine Bedeutung haben (wahrscheinlich) kannst du auch
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;\
foreach (@werte){\
if($_ =~m"<INDEX>(.*)</INDEX>"){\
if ($1 == 1){\
fhem("set aussenwert $val");\
}elsif ($1 == 2){\
fhem("set feuchte $val");\
}elsif ($1 == 3){\
fhem("set ATgestern $val");\
}elsif ($1 == 7){\
fhem("set rain $val");\
}\
}\
$val=$1 if($_ =~m"<VALUE>(.*)</VALUE>");\
}
Ich hoffe, das Prinzip ist zu erkennen. Wo die Werte hin muessen ist mir komplett unklar, daher kann ich nicht weiter helfen.
0.7sec alle 30sec ist immer noch ein hoher Wert, aber du weisst jetzt was es bedeuted und kannst es im Auge behalten.
Gruss, Martin
Hallo Martin,
jetzt habe ich noch einen Fehler beim kopieren gemacht. Mein LogFile zeigt oben immer den neuesten Eintrag an. Das heißt Wirklichkeit steht erst der Index und dann der Value. Was bedeutet, dass der Wert nicht zwischengespeichert werden. Auch richtig ist, dass jeder Wert eine Bedeutung hat.
</WEB>
<PCO>
<ANALOG>
<VARIABLE>
<INDEX>1</INDEX>
<VALUE>-999.9</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>2</INDEX>
<VALUE>37.8</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>3</INDEX>
<VALUE>22.2</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>4</INDEX>
<VALUE>17.5</VALUE>
</VARIABLE>
<VARIABLE>
....
....
</VARIABLE>
</ANALOG>
</PCO>
</WEB>
Jetzt habe ich dies so versucht abzufragen:
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
foreach (@werte){\
if($_ =~m"<INDEX>(.*)</INDEX>"){\
if ($1 == 1){\
fhem("set aussenwert $val");;\
}elsif ($1 == 2){\
fhem("set feuchte $val");;\
}elsif ($1 == 3){\
fhem("set ATgestern $val");;\
}elsif ($1 == 7){\
fhem("set rain $val");;\
}\
}\
$val=$1 if($_ =~m"<VALUE>(.*)</VALUE>");;\
}\
}
Wenn ich das richtig verstehe, fragt doch die Schleife den Index ab und gibt bei entsprechend gefunden Index den dazugehörigen Value aus. Allerdings tut es das nicht. Liegt es daran, dass doch der Index vor dem Value kommt? Wie muss dann der Code angepasst werden?
Danke
Gruß
TinoB
Hi TinoB
ja, die Reihenfolge ist wichtig. Beim Parsen habe ich gespart - und ich dachten es kommt immer erst die Variable, dann der Index.
Du musst dir immer den ersten Wert merken und wenn der 2. da ist schreiben.
Sollte sich die Reihenfolge drehen muss man den (korrekten) weg gehen und alles merken, dann schreiben.
Nachfolgend sollte die Reihenfolge egal sein.
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx && $val){\
if ($idx == 1) {fhem("set aussenwert $val");;\
}elsif ($idx == 2){fhem("set feuchte $val");;\
}elsif ($idx == 3){fhem("set ATgestern $val");;\
}elsif ($idx == 7){fhem("set rain $val");;\
}\
}\
}elsif($_ =~m"<VARIABLE>"){\
$val = $idx = 0;;\
}elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
}if($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
}\
}
Hallo Martin,
Danke für die bisherigen Infos. Nun möchte ich jetzt nicht das Homematic Thema zerschnipseln da die Ursache der Disconnects ja gelöst ist. Allerdings komme ich als noch nicht so großer Perl Spezialist mit dem Code klar.
Bei dem von Dir vorgeschlagenen wird nach der Ausführung weder im Logfile noch im Event Monitor ein Wert ausgegeben.
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx && $val){\
if ($idx == 1) {fhem("set aussenwert $val");;\
}elsif ($idx == 2){fhem("set feuchte $val");;\
}elsif ($idx == 3){fhem("set ATgestern $val");;\
}elsif ($idx == 7){fhem("set rain $val");;\
}\
}\
}elsif($_ =~m"<VARIABLE>"){\
$val = $idx = 0;;\
}elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
}if($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
}\
}\
}
Würdest Du hier bitte nochmals drüber sehen.
Und was passiert eigentlich an dieser Stelle if($_ =~m"</VARIABLE>")? Da geht es doch um die Bedingung welche erfüllt sein muss? Das heißt doch, es wird nach dem Ende des Eintrag </VARIABLE> gesucht? Sehe ich das richtig?
Anschließend kommt die Anweisung if ($idx && $val). Was passiert hier? Bis dahin wurde doch weder ein Index noch Value abgefragt/ermittelt. Und Anschließend kommt doch schon if ($idx == 1) {fhem("set aussenwert $val"), wenn Index 1 dann schreibe Wert.
Danke
Gruß
TinoB
Das vorgehen ist
wenn </VARIABLE> ist der Datensatze beendet. Falls jetzt $idx UND $val gesetzt wurden geben wir es aus
wenn <VARIABLE> beginnt ein neuer Datensatz - wir löschen $idx und $val
wenn "<INDEX>(.*)</INDEX>" setzen wir $idx
wenn "<VALUE>(.*)</VALUE>" setzen wir $val
Diese IFs stehe auf der gleichen Ebene, also wenn das eine
Falsch war
}if($_ =~m"<VALUE>(.*)</VALUE>"){\
sollte sein:
}
elsif($_ =~m"<VALUE>(.*)</VALUE>"){\
ZitatUnd was passiert eigentlich an dieser Stelle if($_ =~m"</VARIABLE>")? Da geht es doch um die Bedingung welche erfüllt sein muss? Das heißt doch, es wird nach dem Ende des Eintrag </VARIABLE> gesucht? Sehe ich das richtig?
korrekt: ein Eintrag der </VARIABLE> beinhaltet
Zitatif ($idx && $val). Was passiert hier?
$idx und $val müssen einen Wert haben, also irgendwann einmal gesetzt worden sein.
ZitatBis dahin wurde doch weder ein Index noch Value abgefragt/ermittelt
ja, im ersten Durchgang nicht. Wir arbeiten aber eine Schleife ab. Es wird Zeile für Zeile durchgegangen. Wenn irgendwann /VARIABLE kommt kamen vorher schon INDEX und VALUE. In welcher Reihenfolge wir die IFs stellen ist nicht wichtig. $val und $idx sind ausserhalb der Schleife definiert und behalten ihren Wert auch im nächsten Durchlauf der Schleife.
ZitatUnd Anschließend kommt doch schon if ($idx == 1) {fhem("set aussenwert $val"), wenn Index 1 dann schreibe Wert.
Die IFs sind geschachtelt. Du musst beachten, was innerhalb weches IFs kommt.
Wenn $idx = 1 dann setze "aussenwert", wenn es 2 ist, dann "feuchte"
zum debuggen kannst du einfach einmal probieren:
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
fhem("set aussenwert varend");;\
}elsif($_ =~m"<VARIABLE>"){\
fhem("set aussenwert varbegin");;\
}elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
fhem("set aussenwert index_$1");;\
}elsif($_ =~m"<VALUE>(.*)</VALUE>"){\
fhem("set aussenwert value_$1");;\
}\
}\
}
Ah Martin spitze, das habe ich verstanden.
könnte es dann sein, dass die Schleife nie abgearbeitet wird, weil die erste Bedingung ein WAHR liefert? Ich hab nun den Code von Dir eingefügt:
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
fhem("set aussenwert varend");;\
}elsif($_ =~m"<VARIABLE>"){\
fhem("set aussenwert varbegin");;\
}elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
fhem("set aussenwert index_$1");;\
}elsif($_ =~m"<VALUE>(.*)</VALUE>"){\
fhem("set aussenwert value_$1");;\
}\
}\
}
und es wird immer nur der erste Wert (varend) ausgegeben. Zum Testen habe ich diesen dann geändert in:
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach (@werte){\
if($_ =~m"<VARIABLE>"){\
fhem("set aussenwert varbegin");;\
}elsif($_ =~m"</VARIABLE>"){\
fhem("set aussenwert varende");;\
}elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
fhem("set aussenwert index_$1");;\
}elsif($_ =~m"<VALUE>(.*)</VALUE>"){\
fhem("set aussenwert value_$1");;\
}\
}\
}
und es wird "varbegin" ausgegeben. Dann zum Testen:
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach (@werte){\
if($_ =~m"<VALUE>(.*)</VALUE>"){\
fhem("set aussenwert value_$1");;\
}elsif($_ =~m"</VARIABLE>"){\
fhem("set aussenwert varende");;\
}elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
fhem("set aussenwert index_$1");;\
}elsif($_ =~m"<VARIABLE>"){\
fhem("set aussenwert varbegin");;\
}\
}\
}
dann wird eben "value_16.7" also wieder der erste ermittelte Wert. Das würde doch eben genau dies bedeuten, die Schleife wird bis zum ersten WAHR abgearbeitet und dann beendet.
Gruß
TinoB
hm - dann wird elsif nicht korrekt verarbeitet.
ersetze doch alle elsif gegen if.
elsif ist "sparsamer", da die Verarbeitung beendet wird. Bei if wird immer noch alles durchgesehen. Aber zum Testen ist es ok.
oder der Kontext geht verloren. dann probieren einmal
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach my $line (@werte){\
if($line =~m"</VARIABLE>"){\
fhem("set aussenwert varend");;\
}elsif($line =~m"<VARIABLE>"){\
fhem("set aussenwert varbegin");;\
}elsif($line =~m"<INDEX>(.*)</INDEX>"){\
fhem("set aussenwert index_$1");;\
}elsif($line =~m"<VALUE>(.*)</VALUE>"){\
fhem("set aussenwert value_$1");;\
}\
}\
}
Wenn elsif durch if ersetzt wird läuft die Schleife durch.
Auch bei dem Test:
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach my $line (@werte){\
if($line =~m"</VARIABLE>"){\
fhem("set aussenwert varend");;\
}if($line =~m"<VARIABLE>"){\
fhem("set aussenwert varbegin");;\
}if($line =~m"<INDEX>(.*)</INDEX>"){\
fhem("set aussenwert index_$1");;\
}if($line =~m"<VALUE>(.*)</VALUE>"){\
fhem("set aussenwert value_$1");;\
}\
}\
}
muss elsif durch if ersetzt werden. Ansonsten wird auch hier nur der erste Wert übergeben.
Jetzt dachte ich versuche es ganz einfach mal so. Es wird nach dem Eintrag INDEX gesucht. Dieser wird in $idx geschrieben und je nach gefundenen $idx wird der VALUE übergeben.
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val;;\
my $idx;;\
foreach (@werte){\
if($_ =~m"<INDEX>(.*)</INDEX>");;\
$idx = $1{\
if($idx == 1){\
if($_ =~m"<VALUE>(.*)</VALUE>"){\
fhem("set aussenwert $1");;\
}\
}\
if($idx == 2){\
if($_ =~m"<VALUE>(.*)</VALUE>"){\
fhem("set feuchte $1");;\
}\
}\
}\
}\
}
Das war dann doch etwas zu einfach ;-) da es so nicht geht :-(
Gruß
TinoB
schade und seltsam dass elsif nicht funktioniert.
Du musst auf die Klammern achten. {} ist immer ein Block. Dein einruecken passt nicht
Du fragst:
foreach (@werte){# fuer jede Zeile
if($_ =~m"<INDEX>(.*)</INDEX>");;\ # ;; ist ende Solle { sein
$idx = $1{\#setze den Index
if($idx == 1){\#falls Index = 1
if($_ =~m"<VALUE>(.*)</VALUE>"){\#und eine value Zeile
...
Probieren einmal:
fuer jede Zeile
--wenn Variable Ende "/VARIABLE"
----Wenn idx und val gesetzt sind (nur dann sollten wir schreiben)
------wenn idx = 1 setze aussenwert
------wenn idx = 2 setze feuchte
----loesche idx und val wenn sie geschrieben wurden
--setze idx falls es eine INDEX Zeile ist
--setze val falls es eine VALUE Zeile ist
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val=0;;\
my $idx=0;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx && $val){\
if ($idx == 1) {fhem("set aussenwert $val");;}\
if ($idx == 2) {fhem("set feuchte $val");;}\
if ($idx == 3) {fhem("set ATgestern $val");;}\
if ($idx == 7) {fhem("set rain $val");;}\
}\
$idx=0;;\
$val=0;;\
}\
if($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
}\
if($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
}\
}\
}
Probleme koennte es geben, wenn der Wert (val) = 0 ist (kein Regen?). Dann wuerde nicht geschrieben. Du kannst daher auch
define html_aufruf_at at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val=0;;\
my $idx=0;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx == 1) {fhem("set aussenwert $val");;}\
if ($idx == 2) {fhem("set feuchte $val");;}\
if ($idx == 3) {fhem("set ATgestern $val");;}\
if ($idx == 7) {fhem("set rain $val");;}\
$idx=0;;\
$val=0;;\
}\
if($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
}\
if($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
}\
}\
}
Gruss Martin
Hallo Martin,
hm, ich versteh das nicht. Es wird weder eine Fehlermeldung noch ein Wert in das LogFile oder auch in den Event Monitor geschrieben. Jetzt habe ich folgenden Test durchgeführt und Log Testidx und Testval eingefügt:
define html_aufruf_test at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my $val=0;;\
my $idx=0;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx && $val){\
if ($idx == 1) {fhem("set aussenwert $val");;}\
if ($idx == 2) {fhem("set feuchte $val");;}\
if ($idx == 3) {fhem("set ATgestern $val");;}\
if ($idx == 7) {fhem("set rain $val");;}\
}\
$idx=0;;\
$val=0;;\
}\
if($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
Log 1, "Testidx $idx";;\
}\
if($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
Log 1, "Testval $val";;\
}\
}\
}
Dabei wird ins LogFile der Index 1 und entsprechende Wert dazu ausgegeben. Was ja sicherlich richtig ist, weil ja dieser als erstes gefunden wird. Ich habe irgendwie das gefühl die Schleife läuft einmal durch und dann nicht mehr. Sonst müsste es doch von vorn wieder losgehen und die entsprechenden Werte zum gesuchten Index gesetzt werden, oder?
Zum Testen wird erst ab Index 2 aufgerufen:
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|2|10");;\
Und auch hier wird der Index 2 und dazugehörige Wert ausgegeben.
Gruß
TinoB
Hallo Toni,
ja, das ist seltsam.
@wert sollte eigentlich ein array aller Zeilen sein.
Ich habe verstanden, dass im logfile
Testidx 2
Testval xxx
auftaucht. Somit wird die schleife 2-mal durchlaufen, aber nicht oefter. Stellt sich die Frage, was eigentlich in @wert steht. 2 Tests sind moeglich, schicke doch die ergebnisse des Logfiles.
Zitatdefine html_aufruf_test at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
Log 1, "Werte ".join '+++',@wert;;\
}
oder/und
Zitatdefine html_aufruf_test at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
foreach my $line (@werte){\
Log 1, "line: $line";;\
}\
}
Gruss Martin
Hallo Martin,
beides liefert folgenden Eintrag zurück:
2013.05.23 20:43:21 1: Werte bzw. line: HTTP/1.0 200 OK
Content-type: text/xml
Cache-Control: no-cache
Expires: -1
<WEB>
<PCO>
<ANALOG>
<VARIABLE>
<INDEX>1</INDEX>
<VALUE>22.1</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>2</INDEX>
<VALUE>21.0</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>3</INDEX>
<VALUE>27.5</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>4</INDEX>
<VALUE>36.4</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>5</INDEX>
<VALUE>-999.9</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>6</INDEX>
<VALUE>20.9</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>7</INDEX>
<VALUE>-999.9</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>8</INDEX>
<VALUE>36.3</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>9</INDEX>
<VALUE>21.7</VALUE>
</VARIABLE>
<VARIABLE>
<INDEX>10</INDEX>
<VALUE>10.2</VALUE>
</VARIABLE>
</ANALOG>
</PCO>
</WEB>
Gruß
TinoB
Hi Toni,
wenn dies die Antwort aus beiden Abfragen ist bedeuted es, dass nicht ein Array sondern ein String zurueckgegeben wird.
Daher hat auch bislang alles nicht funktioniert. In der Loop war nur ein Element mit mehreren Zeilen.
Wir muessen also erst einmal die Struktur analysieren und dann den String in ein array zerlegen.
Um sicher zu gehen, dass es nur ein Element ist hier ein Test:
Zitatdefine html_aufruf_test at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
Log 1, "Elemente: ".scalar(@wert);;\
}
Es sollte "Elemente: 1" gelogt werden.
Nun muessen wir also den String in Zeilen zerlegen. Gehen wir davon aus, dass jede Zeile mit einem \n endet, dann sieht es so aus:
define html_aufruf_test at +*00:00:30 {\
my @ret=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my @werte=split "\n",$ret[0];;\
my $val=0;;\
my $idx=0;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx && $val){\
if ($idx == 1) {fhem("set aussenwert $val");;}\
if ($idx == 2) {fhem("set feuchte $val");;}\
if ($idx == 3) {fhem("set ATgestern $val");;}\
if ($idx == 7) {fhem("set rain $val");;}\
}\
$idx=0;;\
$val=0;;\
}\
if($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
Log 1, "Testidx $idx";;\
}\
if($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
Log 1, "Testval $val";;\
}\
}\
}
Dann sollte auch das elsif funktionieren. Das war sicher kein Fehler sondern der Input war nicht verstanden.
Zitatdefine html_aufruf_test at +*00:00:30 {\
my @werte=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
Log 1, "Elemente: ".scalar(@wert);;\
}
Es sollte "Elemente: 1" gelogt werden.
Nun muessen wir also den String in Zeilen zerlegen. Gehen wir davon aus, dass jede Zeile mit einem \n endet, dann sieht es so aus:
define html_aufruf_test at +*00:00:30 {\
my @ret=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my @zeile=split "\n",$ret[0];;\
my $val=0;;\
my $idx=0;;\
foreach (@zeile){\
if($_ =~m"</VARIABLE>"){\
if ($idx && $val){\
if ($idx == 1) {fhem("set aussenwert $val");;}\
elsif ($idx == 2) {fhem("set feuchte $val");;}\
elsif ($idx == 3) {fhem("set ATgestern $val");;}\
elsif ($idx == 7) {fhem("set rain $val");;}\
}\
$idx=0;;\
$val=0;;\
}\
elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
Log 1, "Testidx $idx";;\
}\
elsif($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
Log 1, "Testval $val";;\
}\
}\
}
Gruss
Martin
Hi Martin,
ja, das Splitten habe ich verstanden. Es werden nun auch alle gesuchten Werte zum jeweiligen Index ausgegeben.
Eines habe ich jedoch genau Deine Befürchtung festgestellt.
ZitatProbleme koennte es geben, wenn der Wert (val) = 0 ist (kein Regen?). Dann wuerde nicht geschrieben. Du kannst daher auch
Hat ein Wert einmal eine 1 angenommen, bleibt dieser für immer stehen und die Triggertime wird nicht mehr aktualisiert. Der Wert selbst ist jedoch inzwischen wieder eine 0. Hat es damit etwas zu tun?
.....
if ($idx == 7) {fhem("set rain $val");;}\
}\
$idx=0;;\
$val=0;;\
}\
if($_ =~m"<INDEX>(.*)</INDEX>"){\
....
Was bedeutet das? Der Wert wird nach dem Durchlauf dann immer wieder auf 0 gesetzt? Zumindest funktioniert das so nicht.
Gruß
Tino
wenn die Werte geschrieben wurden 'lösche' ich sie. Ist sauberer.
Du kannst folgendes machen:
nur auf den index abfragen, also
if ($idx && $val){\
ersetzen durch
if ($idx){\
dann kannst du noch
$val=0;;\
ersetzen durch beispielsweise
$val=999;;\
damit erkennst du, ob es ein Problem bei der Übertragung gegeben hat. Wenn kein Wert geliefert wird bekommst du 999 (oder einen Wert wie du willst).
Beispiel: Wenn der Wert fehlt, keine Ausgabe:
define html_aufruf_test at +*00:00:30 {\
my @ret=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my @werte=split "\n",$ret[0];;\
my $val=0;;\
my $idx=0;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx && $val != 999){\
if ($idx == 1) {fhem("set aussenwert $val");;}\
elsif ($idx == 2) {fhem("set feuchte $val");;}\
elsif ($idx == 3) {fhem("set ATgestern $val");;}\
elsif ($idx == 7) {fhem("set rain $val");;}\
}\
$idx=0;;\
$val=999;;\
}\
elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
Log 1, "Testidx $idx";;\
}\
elsif($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
Log 1, "Testval $val";;\
}\
}\
}
oder bei einem Fehler ausgaben des defaults (hier 999)
define html_aufruf_test at +*00:00:30 {\
my @ret=GetHttpFile("192.168.1.150", "/usr-cgi/xml.cgi?|A|1|10");;\
my @werte=split "\n",$ret[0];;\
my $val=0;;\
my $idx=0;;\
foreach (@werte){\
if($_ =~m"</VARIABLE>"){\
if ($idx){\
if ($idx == 1) {fhem("set aussenwert $val");;}\
elsif ($idx == 2) {fhem("set feuchte $val");;}\
elsif ($idx == 3) {fhem("set ATgestern $val");;}\
elsif ($idx == 7) {fhem("set rain $val");;}\
}\
$idx=0;;\
$val=999;;\
}\
elsif($_ =~m"<INDEX>(.*)</INDEX>"){\
$idx = $1;;\
Log 1, "Testidx $idx";;\
}\
elsif($_ =~m"<VALUE>(.*)</VALUE>"){\
$val = $1;;\
Log 1, "Testval $val";;\
}\
}\
}
Hallo Martin,
Danke für Deine Hilfe. Es tut was es soll.
Eine letzte Anfrage noch dazu:
ZitatWenn es daran liegt wie lange dein device zum Antworten braucht sollte man den Prozess auslagern. Das ist auf User-level etwas komplexer (jedenfalls habe ich noch nicht nachgedacht darüber).
Meinst Du damit die Auslagerung in ein Modul?
Danke,
Gruß
TinoB
Hallo TinoB,
nein, auslagern in einen anderen Prozess - ist hier zu kompliziert, besonders wenn es so funktioniert.
Zum Verstaendniss - manchmal muss man auf Antworten warten, so wie in deinem Fall. Wenn man aktiv wartet steht der Prozess und keiner kann mehr etwas machen bis es Warten beendet ist. Manchmal kann man passiv warten, sprich man startet und schaut nach ob ein Ergebnis nach einer Zeit eingetroffen ist - oder wird vom Ergebniss geweckt. Hierbei arbeitet der Process weiter an anderen Aufgaben.
FHEM ist (im Wesentlichen) nur ein Prozess. Wenn man also aktiv wartet (warten muss wie in deinem Fall auf die Antwort des 'Ethernet') bleibt alles andere liegen.
Man kann das Warten auch auslagern, also einen 2. Prozess starten. Dann kann der hauptprozess weiter arbeiten. Der 2. muss dann irgendwann sein Ergebniss an den Ersten ruecksenden.
FHEM hat mittlerweile Mechanismen um ein paar Dinge 'auszulagern' in einen 2. Prozess.
Module in FHEM arbeiten alle in einem Prozess - das wuerde also nichts bringen.
Gruss Martin
Hallo Martin,
Danke für die Erklärung. Das würde ja bedeuten, dass immer nur ein Prozess nach dem anderen abgearbeitet würde. Das würde doch dann wiederum aber auch bedeuten, dass wenn zu viele Prozesse in FHEM integriert sind, dann FHEM irgendwann überfordert ist. Ist das dann auch abhängig vom System? Also in meinem Fall einer FritzBox. Die macht ja nebenbei auch noch andere Dinge.
Ein Beispiel wo mir dies in FHEM aufgefallen ist, beim Plotaufruf von zu großen Logdateien steigt HMLAN ebenfalls mit den Disconnects aus. Also wenn dieser eine gewisse Zeit übersteigt.
Somit kann man dies dann nur mit Tunning umgehen. Richtig? Aber irgendwann kann man dann tunnen wie man will, wenn zu viele Aufgaben anstehen. Richtig? Das System ist also irgendwann voll.
Ist dann sozusagen wie im richtigen Leben, irgendwann ist dann eine Überforderung da, wenn man zu viel will ;-)
Danke
Gruß,
TinoB
Hallo TinoB,
Zum einen hast du eine begrenzte Anzahl CPUs (die FB nur eine). Linux auf der FB verwaltet alle Prozesse und steuert, wer dran kommt. Da kommen wir nicht vorbei, FHEM muss sich mit den anderen Processen arrangieren.
FHEM läuft primär in einem Prozess, nur in Ausnahmen werden anderen Prozesse gestartet. Also alle Aufgaben werden innerhalb FHEM nacheinander abgearbeitet.
Der Plot laeuft im FHEM Prozess. Es sind hier viele Dinge zu berücksichtigen
- die benötigte CPU zeit wird benötigt, da geht nichts vorbei
- falls der Task warten muss, muss dies auch FHEM (wie bei deinem Problem)
Generell ist deine Beschreibung korrekt. Was man in einem sicherheitsrelevanten Echtzeitsystem machen muesste ist, alle backend Tasks in low-prio Processe auslagern, eine ganze Struktur von Processen starten (schon das Schreiben auf ein File sollte nicht mit der Kommunikation und den Schaltkommandos auf einem Level stehen). Eine inter-prozess kommunikation aufbauen, damit sich die Prozesse unterhalten koennen.
Das waere ziemlich viel Arbeit. Dennoch koennte ein Prozess, der nicht zu FHEM gehört alles zu nichte machen.
Erste Aktionen sind im werden, dass herausragend lange wartende Tasks ausgelagert werden.
Gruss Martin