Heizungssteuerung mit VCLIENT (Version 0.2.11f)

Begonnen von andies, 16 Oktober 2017, 21:51:13

Vorheriges Thema - Nächstes Thema

phantom

So,  der 0,1-Bug ist gefunden  :D  . 
Ich habe die Abfrage in Zeile 635 von  if (!$arg)  auf  if ( ($arg eq "0") && ($arg != 0) )  geändert, damit auch die Null als Zahl und nicht als Text wie bei Timern behandelt wird. Damit klappt das Setzen der binären Stati.

Dein Einwand mit dem doppelten  gettimeofday()  ist korrekt. Das zweite muss raus.
mit etwas verlängerten Timings läuft es stabiler und nun ohne shutdown's  :D
attr timeout :   2
attr internal_update_interval :   0.2

dies scheint jedoch nur nötig, wenn auch andere den vcontrold ebenfalls mit vielen Werten abfragen

Dann habe ich noch minimale Anpassungen gemacht:
- bei reload_command_file ohne Filename,  den Default $filename aus DEF nehmen.  (Zeile 610-613)
- und die hardcodierte Änderung für die Betriebsarten u. Stati ist durch eine Abfrage auf Temperaturwerte ersetzt
  damit werden Temperaturen auf eine Nachkommastelle und sonstige Stati ohne Nachkommastelle ausgegeben
  das sollte besser sein, wie beim Integritätscheck der Temperaturen  (s. Zeile 401-408)
- flexbilerer Status-Check in Zeile 326

Alle genannten Zeilennummern beziehen sich auf die modifizierte, angehängte Version.
Darin sind die o.g. Fehlerbehebungen und kl. Anpassungen schon drin. (vergleichs mal mit deiner letzten Version)

Gruß Phantom

andies

Super, danke - jetzt machst Du meine Arbeit...

Übernehme ich alles und werde das in dem ersten Post anpinnen.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

phantom

Hi Andi,

alles gut, dafür ist die Community da ;-)

Ich habe das Modul VCLIENT.pm nun seit einigen Tage problemlos in Betrieb. Wenn man recht viele Werte (z.B. alle Stati und Timer) aus abrufen will, klappt es zuverlässiger, wenn man der Viessmann-Steuerung "etwas Zeit gibt". (s. vorheriges Posting).

Evtl. könntest du das Modul auch ins allgemeine Repository einchecken. Dann finden es andere interessierte leichter  ;)

Gruß Phantom

andies

Zitat von: phantom am 17 Dezember 2018, 18:58:39
Evtl. könntest du das Modul auch ins allgemeine Repository einchecken. Dann finden es andere interessierte leichter  ;)

Gruß Phantom
An wen muss ich mich wenden? und was müsste da noch getan werden?
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

CoolTux

Das Modul benötigt auf jeden Fall eine Commandref sofern noch nicht vorhanden. Du musst Schreibrechte für das SVN beantragen
https://svn.fhem.de/

Und Du suchst Dir einen erfahrenden Developer der sich Dein Modul einmal an schaut.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

andies

So, ich habe das Modul jetzt im offiziellen FHEM-Bereich. Daher schließe ich diesen Thread. Fehlermeldungen etc bitte hier:

https://forum.fhem.de/index.php/topic,94809.msg875808.html#msg875808

PS Phantom, du musst aufpassen. Ich habe vermutlich eine Deiner Änderungen nicht übernommen und daher musst Du VCLIENT beim update ausschließen, sonst wird das überschrieben:
attr global exclude_from_update 89_VCLIENT.pm
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Zitat von: CoolTux am 18 Oktober 2017, 21:11:52
So kann man es machen.
CoolTux, ich brauche mal Deinen Rat. Das Modul läuft ja nun schon eine ganze Weile und ist auch ok, aber ab und an gibt es bei mir Timeouts, die dann dazu führen, dass das gesamte FHEM "steht". Nun habe ich einen Programmierfehler bei mir bemerkt und dachte: "Kein Wunder, aber jetzt läuft es" und das ist aber nicht der Fall. Vielleicht hast Du eine Idee, wo ich suchen kann?

Also, zum Programmablauf. Das Modul erhält zB den Befehl die readings zu aktualisieren. Dann wird der Prozess angestoßen und die von vcontrold durchzuführenden Befehle werden in einer command_queue notiert. Das aufbauen dieses hash geht sofort und nicht-blockierend. Danach gibt es einen hash mit Befehlen, die auszuführen sind.

Dann wird jeder Befehl einzeln an vcontrold geschickt, nur einmal und es wird gewartet, bis eine Rückmeldung läuft. Konkret, es wird gesetzt
sub VCLIENT_Set_New_Write_Interval($)
{
my ($hash) = @_;
my $name = $hash->{NAME} ;

#remove old timout
RemoveInternalTimer($hash);

#set up timer for writing next signal (fixed at $internal_update_interval seconds after opening connection)
my $my_internal_timer = AttrVal( $name, 'internal_update_interval', $internal_update_interval);
InternalTimer(gettimeofday()+ $my_internal_timer, "VCLIENT_Write", $hash);
}

und dann wird ein Flag notiert "reading_in_progress". Ist der 1, passiert nichts. Ist der 0, wird gesendet:
sub VCLIENT_Write($)
{
    my ($hash) = @_;     
    my $name = $hash->{NAME}; #Name des devices
    my $msg = "OK";       # Variable, um Rückgabe des Schreibvorgangs auszuwerten

    #Ist es moeglich, die Verbindung zu oeffnen?
if (!$hash->{CD}){
        $msg = VCLIENT_Open_Connection($hash); #gibt Error im Fehlerfall zurueck und bricht intern ab, sonst OK
    }

    if ($msg eq "OK"){
#wenn ein Befehl abgesendet wurde und noch keine Rueckgabe erfolgte, write nicht ausfuehren, sondern verzoegern (=erneut aufrufen)
    if ($reading_in_progress){
    VCLIENT_Set_New_Write_Interval($hash); # siehe oben, da wird einfach der time geloescht und ein neuer definiert; mehr nicht
    return;
    }

    #jetzt wird das Kommando eingelesen, das gesendet werden soll
    $last_cmd = shift @command_queue;  #global variable, if this command was not recognized by vcontrold there must be an error message in VCLIENT_Read

if ($last_cmd){ # wenn es noch ein Kommando gibt, loslegen!
#send signal
Log3 $name, 5,  "$name: Requesting ".$last_cmd." now";
$last_cmd .= "\r\n"; #Zeilenende hinzufuegen
#flag because we need to stop sending until next timeout / successful reading, do this BEFORE syswrite
$reading_in_progress = 1; #flag setzen
syswrite($hash->{CD}, $last_cmd); #der eigentliche sendebefehl
    #and set timer for timeout
    RemoveInternalTimer($hash); #alten timeout loeschen
    my $this_timeout = AttrVal( $name, 'timeout', 5); #neuen timeout setzen, falls gar keine Rueckmeldung erfolgt, default value is 5 second
    InternalTimer(gettimeofday()+$this_timeout, "VCLIENT_Timeout", $hash);
} else {
#last command already executed, set now timer for closing
    RemoveInternalTimer($hash); #das naechste update-Intervall setzen
   my $my_internal_timer = AttrVal( $name, 'internal_update_interval', $internal_update_interval);
    InternalTimer(gettimeofday()+ $my_internal_timer, "VCLIENT_Close_Connection", $hash);
}
    }
}


Es kommt nun vor, dass anscheinend die Verbindung zusammenbricht, wie der folgende Log zeigt:
2019.05.22 18:13:32 5: Viessmann: will now update readings
2019.05.22 18:13:36 5: Viessmann: Opening vcontrold connection to 192.168.2.105:3002
2019.05.22 18:13:36 5: Viessmann: vcontrold opened
2019.05.22 18:13:36 5: Viessmann: Requesting getBrennerStunden1 now
2019.05.22 18:13:47 3: Viessmann: Received 20472 for Stunden
2019.05.22 18:14:00 5: Viessmann: Requesting getTempKist now
2019.05.22 18:14:14 3: Viessmann: Received 53.3 for Kesseltemperatur
2019.05.22 18:14:34 5: Viessmann: Requesting getTempAbgas now
2019.05.22 18:14:39 3: Viessmann: Received 60.5 for Abgastemperatur
2019.05.22 18:14:49 5: Viessmann: Requesting getTempA now
2019.05.22 18:15:00 3: Viessmann: Received 13.6 for Aussentemperatur
2019.05.22 18:15:15 5: Viessmann: Requesting getBrennerStarts now
2019.05.22 18:15:29 3: Viessmann: Received 191232 for Starts
2019.05.22 18:15:46 5: Viessmann: Requesting getTempWWist now
2019.05.22 18:16:00 3: Viessmann: Received 58.7 for Warmwassertemperatur
2019.05.22 18:16:26 5: Viessmann: Closing vcontrold connection
2019.05.22 18:26:31 5: Viessmann: will now update readings
2019.05.22 18:26:34 5: Viessmann: Opening vcontrold connection to 192.168.2.105:3002
2019.05.22 18:26:34 5: Viessmann: vcontrold opened
2019.05.22 18:26:34 5: Viessmann: Requesting getBrennerStunden1 now
2019.05.22 18:26:46 3: Viessmann: Received 20472 for Stunden
2019.05.22 18:27:00 5: Viessmann: Requesting getTempKist now
2019.05.22 18:27:16 3: Viessmann: Received 50.5 for Kesseltemperatur
2019.05.22 18:27:23 5: Viessmann: Requesting getTempAbgas now
2019.05.22 18:27:34 1: Viessmann timeout: Was not able to receive a signal from 192.168.2.105:3002. Deleting command queue. <=== HIER
2019.05.22 18:27:34 5: Viessmann: Closing vcontrold connection

Ich verstehe nun nicht, warum an der Stelle FHEM oder genauer perl auf 100% CPU hochläuft. Da blockiert doch nichts?! syswrite ist durch und die Schleife wartet nur, ob irgendwann etwas zum lesen hineinkommt. Wenn nichts hineinkommt, sollte das normale FHEM weiterlaufen und gut ist. Das ist aber nicht der Fall?!

Read sieht so aus:
sub VCLIENT_Read($){
    my ($hash) = @_;
    my $name = $hash->{NAME};

my $buf;
my $line = sysread($hash->{CD}, $buf, 1024);

    if ( !defined($line) || !$line){
$reading_in_progress = 0; #enforce finish reading
Log3 $name, 5,  "$name: connection closed unexpectedly"; #kann hier eigentlich nicht passieren
VCLIENT_Close_Connection($hash);
return;
    }

unless (defined $buf){
Log3 $name, 5,  "$name: no data received"; #continue reading
return;
}

        ## debug #######################
        ##Log3 $name, 1, $name." raw \$buf = ".$buf;

#remove prompt and trailing empty lines, auch https://forum.fhem.de/index.php?topic=100698
$buf =~ s/\r//g;
$buf =~ s/vctrld>//g;
$buf =~ s/\n$//;

if ($buf ne "") {
#erst hier kommen echte Daten an, die ins Reading geschrieben werden sollen - nur diese parsen
VCLIENT_ParseBuf_And_WriteReading($hash, $buf);
}
$reading_in_progress = 0; #reading successfully finished
}

und Timeout sieht so aus:
sub VCLIENT_Timeout($)
{
    my ($hash) = @_;
   
    my $name = $hash->{NAME};
    my $host = $hash->{IP};
    my $port = $hash->{PORT};
    my $interval = $hash->{INTERVAL};
    my $telnet = $hash->{CD};

    Log3 $name, 1, $name." timeout: Was not able to receive a signal from $host:$port. Deleting command queue.";
    @command_queue = ();
@reading_queue = ();
$reading_in_progress = 0;
    if ($telnet){ #wenn Verbindung existent
if ($telnet->open($host)){ # und offen
VCLIENT_Close_Connection($hash);
}
    }

    readingsSingleUpdate($hash, "state", "timeout", 1);
    #set new update interval
    VCLIENT_Set_New_Update_Interval($hash); 
}


Also, lange Rede, kurze Frage: Hast Du eine Idee, wieso bei nichterreichen des fremden Hosts die CPU-Last auf 100% geht und FHEM faktisch blockiert ist?

PS Das Modul ist ja im svn eingecheckt...
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

mumpitzstuff

sysread blockiert, wenn keine Daten kommen, soweit ich weiß.

use IO::Select;

my $select = IO::Select->new($hash->{CD});

if ($select->can_read(0.1))
{
      sysread($hash->{CD}, $ret, 1024);
      ...
}


Hier mal exemplarisch wie man das umgehen könnte, wenn das die Ursache ist.

andies

Aaah, das kann es sein. Danke! Schaue ich mir mal genauer an. Das passt.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

CoolTux

#84
Da die ReadFn nur aufgerufen wird wenn Daten zur Verfügung stehen sollte das mit sysread eigentlich unerheblich sein

Ich schaue nachher mal drüber.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

CoolTux

Ich kann nicht wirklich was finden.

2 Möglichhkeiten

1. mumpitzstuff seine Variante funktioniert, dann lag es am sysread. Teste das bitte einmal. Ich tippe allerdings darauf das es das nicht ist.
2. Das syswrite hat Probleme seine Daten los zu werden. Daher springt Dein Timeout auch an. Würde ja Sinn machen wenn vcontrold die Verbindung kappt und FHEM das nicht mit bekommt.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

andies

Zitat von: CoolTux am 23 Mai 2019, 08:21:51
Das syswrite hat Probleme seine Daten los zu werden.
Das kann ich ja testen mit
ZitatThis function returns undef on error and Integer, number of bytes written on success.
Aber blockiert syswrite? Oder gibt es eine Möglichkeit analog oben, wo ich einen möglichen Schreibfehler abfangen kann?
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

CoolTux

Bin mir nicht sicher aber ich würde sagen das syswrite blockiert wenn der Socket nicht offen ist.
Bin mir gerade unsicher, aber du testest ja schon ob der Socket da ist, zu mindest mittels $hash->{CD}
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

andies

Zitat von: CoolTux am 23 Mai 2019, 18:23:29
Bin mir nicht sicher aber ich würde sagen das syswrite blockiert wenn der Socket nicht offen ist.
Also, ich habe das mal über Nacht laufen lassen. Syswrite ist es anscheinend nicht. Hier der Code

Log3 $name, 1, "DEBUG will syswrite  ".$last_cmd;
my $bytes_written=syswrite($hash->{CD}, $last_cmd);
Log3 $name, 1, "DEBUG syswrite bytes written ".$bytes_written;


und dazu der Logfile, wobei ich die Zeilenvorschübe nach dem Befehl entfernt und dafür andere Zeilenvorschübe der Übersichtlichkeit eingefügt habe. Man sieht, dass die abgeschickten Zeichen sofort gesendet werden:

2019.05.24 04:06:23 1: DEBUG will syswrite  getBrennerStunden1
2019.05.24 04:06:23 1: DEBUG syswrite bytes written 20

2019.05.24 04:17:08 1: DEBUG will syswrite  getTempWWist
2019.05.24 04:17:08 1: DEBUG syswrite bytes written 14

2019.05.24 04:17:31 1: DEBUG will syswrite  getTempA
2019.05.24 04:17:31 1: DEBUG syswrite bytes written 10

2019.05.24 04:17:58 1: DEBUG will syswrite  getBrennerStarts
2019.05.24 04:17:58 1: DEBUG syswrite bytes written 18
2019.05.24 04:18:18 1: Viessmann timeout: Was not able to receive a signal from 192.168.2.105:3002. Deleting command queue.

2019.05.24 04:28:51 1: DEBUG will syswrite  getTempWWist
2019.05.24 04:28:51 1: DEBUG syswrite bytes written 14

2019.05.24 04:29:03 1: DEBUG will syswrite  getTempA
2019.05.24 04:29:03 1: DEBUG syswrite bytes written 10

2019.05.24 04:29:14 1: DEBUG will syswrite  getBrennerStarts
2019.05.24 04:29:14 1: DEBUG syswrite bytes written 18


Dann bleibt doch erstmal nur noch die Vermutung von mumpitzstuff? Die werde ich jetzt mal umsetzen.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Zitat von: mumpitzstuff am 23 Mai 2019, 03:07:48
sysread blockiert, wenn keine Daten kommen, soweit ich weiß.
Bist Du Dir sicher, dass fehlende Daten mein Problem sind? Ich habe ein wenig gelesen und mir nochmal meine empfangenen Daten angeschaut (ich kenne mich mit IO::Select nicht aus), und ich vermute, dass (nur) das Zeilenende \n nicht empfangen wird und Perl\FHEM dann darauf wartet und blockiert. Das würde jedenfalls zu meinen Fehlerbildern passen. Wenn das das Problem sein sollte, muss ich aber anders vorgehen als in Deinem Code: Ich müsste lesen, was zu lesen ist und dann, wenn kein \n kommt, beenden.

Hast Du einen Link, wo ich dazu was finde? Die Perl-Doc ist etwas zu rudimentär für mich.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann