From 62fe7bb3aeecc8121dcf7f99b6bcdfaeb4eb14bd Mon Sep 17 00:00:00 2001 From: andies <> Date: Sun, 26 May 2019 10:01:51 +0000 Subject: [PATCH] https://forum.fhem.de/index.php/topic,78101.msg943114.html#msg943114 git-svn-id: https://svn.fhem.de/fhem/trunk@19469 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/89_VCLIENT.pm | 68 +++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/fhem/FHEM/89_VCLIENT.pm b/fhem/FHEM/89_VCLIENT.pm index dc3b1cb8d..376c09ed4 100644 --- a/fhem/FHEM/89_VCLIENT.pm +++ b/fhem/FHEM/89_VCLIENT.pm @@ -50,7 +50,9 @@ # # Version History # -# 2019-05-19 version 0.2.12a: major bug removed when syswrite impossible +# 2019-05-24 version 0.2.13: bug with blocking sysread, see https://forum.fhem.de/index.php?topic=100698 +# 2019-05-21 version 0.2.12d: minor detail using $buf, https://forum.fhem.de/index.php?topic=100698 +# 2019-05-19 version 0.2.12: major bug removed when syswrite impossible # 2019-03-27 version 0.2.11k: error message instead of debug # 2019-01-28 version 0.2.11j: vcontrold-Neigung (Heizkurve) commands not rounded to full number anymore # 2019-01-28 version 0.2.11i: update starts now if device initiated (for example, via FHEM restart) @@ -75,8 +77,9 @@ use warnings; use Scalar::Util qw(looks_like_number); use Blocking; use Data::Dumper; +use IO::Select; -my $VCLIENT_version = "0.2.12a"; +my $VCLIENT_version = "0.2.13"; my $internal_update_interval = 0.1; #internal update interval for Write (time between two different write_to_Viessmann commands) my $daily_commands_last_day_with_execution = strftime('%d', localtime)-1; #last day when daily commands (commands with type 'daily' ) were executed; set to today @@ -359,7 +362,7 @@ sub VCLIENT_Open_Connection($) my $host = $hash->{IP}; my $port = $hash->{PORT}; - my $timeout = AttrVal( $name, 'timeout', 1); #default value is 1 second + my $timeout = AttrVal( $name, 'timeout', 5); #default value is 5 seconds my $t_prompt = AttrVal($name,'prompt',$hash->{'.prompt'}); Log3 $name, 5, "$name: Opening vcontrold connection to $host:$port"; my $telnet = new Net::Telnet ( Port => $port, Timeout=>$timeout, Errmode=>'return', Prompt=>'/'.$t_prompt.'/', Dump_Log => '/opt/fhem/log/vcontrold.log'); @@ -393,12 +396,15 @@ sub VCLIENT_Open_Connection($) sub VCLIENT_ParseBuf_And_WriteReading($$){ my ($hash, $buf) = @_; my $name = $hash->{NAME}; + my $value; #zu speichernder Wert my $reading = shift @reading_queue; #Readingname, dorthin sollen Daten gespeichert werden - my $value; #zu speichernder Wert + if (!$reading){ + return; #keine reading queue mehr vorhanden, Aufruf vermutlich nach timeout + } #Ergebnis = Kommando war fehlerhaft - if ($buf eq "ERR: command unknown"){ + if ($buf eq "ERR: command unknown"){ $value = "ERROR, see logfile"; Log3 $name, 1, "$name ERROR: command ".$last_cmd." from ".$hash->{FILE}." does not seem to be defined in vcontrol.xml"; } else { @@ -446,10 +452,12 @@ sub VCLIENT_ParseBuf_And_WriteReading($$){ } Log3 $name, 3, $name.": Received ".$value." for ".$reading; } - if (($value eq "OK") or VCLIENT_integrity_check($value)) + + if (VCLIENT_integrity_check($value)) { readingsSingleUpdate($hash, $reading, $value, 1); } + VCLIENT_Set_New_Write_Interval($hash); } @@ -461,30 +469,31 @@ sub VCLIENT_ParseBuf_And_WriteReading($$){ sub VCLIENT_Read($){ my ($hash) = @_; my $name = $hash->{NAME}; + my $buf; + my $select = IO::Select->new($hash->{CD}); # see forum, blocking call with empty sysread - my $buf; - my $line = sysread($hash->{CD}, $buf, 1024); + if ($select->can_read(0.1)) #timeout 0.1 Sekunden, FHEM blockiert sonst! + { + 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 + $reading_in_progress = 0; + + if (!$buf){ + Log3 $name, 1, "Error: empty buffer while sysread"; #kann hier eigentlich nicht passieren VCLIENT_Close_Connection($hash); return; } - unless (defined $buf){ - Log3 $name, 5, "$name: no data received"; #continue reading - return; - } - - #remove prompt and empty lines (with and without newline) - $buf =~ s/(vctrld>[\r]?[\n]?)*//; + #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 + if ($buf ne '') { + #wenn nach remove echte Daten ankommen, die ins Reading geschrieben werden sollen - diese parsen VCLIENT_ParseBuf_And_WriteReading($hash, $buf); - } - $reading_in_progress = 0; #reading successfully finished + } } @@ -664,8 +673,8 @@ sub VCLIENT_Set($@) $arg =~ s/[-\|]/ /g; # Zeitabstandszeichen - und senkrechten Strich | durch Leerzeichen ersetzen } Log3 $name, 5, $name.": will try to send command ".$vcontrold." ".$arg." now"; - #Debug ($name.": next command in queue ".$vcontrold." ".$arg); - readingsSingleUpdate($hash, "last_set_command", "cmd: ".$vcontrold." ".$arg." ...", 1); + ###debug Log3 $name, 1, $name.": next command in queue ".$vcontrold." ".$arg); + readingsSingleUpdate($hash, "last_set_command", $vcontrold." ".$arg, 1); ##$reading_in_progress = 0; ### Ich glaube, das kann man ausblenden, denn es gibt eine Rueckmeldung naemlich ein OK ########### push @command_queue, $vcontrold." ".$arg; @@ -895,10 +904,11 @@ sub VCLIENT_Write($) $last_cmd .= "\r\n"; #flag because we need to stop sending until next timeout / successful reading, do this BEFORE syswrite $reading_in_progress = 1; + syswrite($hash->{CD}, $last_cmd); - #and set timer for timeout + #and set timer for timeout RemoveInternalTimer($hash); - my $this_timeout = AttrVal( $name, 'timeout', '1'); #default value is 1 second + my $this_timeout = AttrVal( $name, 'timeout', 5); #default value is 5 second InternalTimer(gettimeofday()+$this_timeout, "VCLIENT_Timeout", $hash); } else { #last command already executed, set now timer for closing @@ -1004,13 +1014,13 @@ The set command can also be used to execute vcontrold commands. These commands m