diff --git a/fhem/CHANGED b/fhem/CHANGED index dd573222e..f99992aa3 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,8 +1,9 @@ # Add changes at the top of the list. Keep it in ASCII - SVN + - feature: updateInBackground global attribute - feature: SYSSTAT: allow stateFormat - - feature: Module 70_VIERA supports now module 95_remotecontrol with own layout - for VIERA TV + - feature: Module 70_VIERA supports now module 95_remotecontrol with own + layout for VIERA TV - feature: InternalVal function added (like ReadingsVal) - feature: new module speedtest to monitor internet connection speed with speedtest-cli diff --git a/fhem/FHEM/01_FHEMWEB.pm b/fhem/FHEM/01_FHEMWEB.pm index 34f63adf2..05f39ae44 100755 --- a/fhem/FHEM/01_FHEMWEB.pm +++ b/fhem/FHEM/01_FHEMWEB.pm @@ -75,6 +75,7 @@ use vars qw(%FW_webArgs); # all arguments specified in the GET my $FW_zlib_checked; my $FW_use_zlib = 1; +my $FW_activateInform = 0; ######################### # As we are _not_ multithreaded, it is safe to use global variables. @@ -113,6 +114,7 @@ FHEMWEB_Initialize($) $hash->{DefFn} = "FW_Define"; $hash->{UndefFn} = "FW_Undef"; $hash->{NotifyFn}= "FW_SecurityCheck"; + $hash->{ActivateInformFn} = "FW_ActivateInform"; $hash->{AttrList}= "loglevel:0,1,2,3,4,5,6 webname fwcompress:0,1 ". "plotmode:gnuplot,gnuplot-scroll,SVG plotsize endPlotToday:1,0 plotfork ". @@ -554,6 +556,11 @@ FW_answerCall($) "onload=\"FW_delayedStart()\"" : ""; FW_pO "\n"; + if($FW_activateInform) { + $FW_cmdret = $FW_activateInform = ""; + $cmd = "style eventMonitor"; + } + if($FW_cmdret) { $FW_detail = ""; $FW_room = ""; @@ -2406,7 +2413,11 @@ FW_Notify($$) # Collect multiple changes (e.g. from noties) into one message $ntfy->{INFORMBUF} .= $data; RemoveInternalTimer($ln); - InternalTimer(gettimeofday()+0.1, "FW_FlushInform", $ln, 0); + if(length($ntfy->{INFORMBUF}) > 1024) { + FW_FlushInform($ln); + } else { + InternalTimer(gettimeofday()+0.1, "FW_FlushInform", $ln, 0); + } } return undef; @@ -2674,6 +2685,12 @@ FW_dropdownFn() return undef; } +sub +FW_ActivateInform() +{ + $FW_activateInform = 1; +} + 1; =pod diff --git a/fhem/FHEM/98_backup.pm b/fhem/FHEM/98_backup.pm index c4a696bf2..d120c76e5 100644 --- a/fhem/FHEM/98_backup.pm +++ b/fhem/FHEM/98_backup.pm @@ -163,6 +163,7 @@ createArchiv($) $dateTime =~ s/ /_/g; $dateTime =~ s/(:|-)//g; + my $cmd=""; if (!defined($backupcmd)) { if (lc($symlink) eq "no") { $tarOpts = "cf"; @@ -171,10 +172,13 @@ createArchiv($) } # prevents tar's output of "Removing leading /" and return total bytes of archive - $ret = `(tar -$tarOpts - @pathname | gzip > $backupdir/FHEM-$dateTime.tar.gz) 2>&1`; + $cmd = "tar -$tarOpts - @pathname |gzip > $backupdir/FHEM-$dateTime.tar.gz"; } else { - $ret = `($backupcmd "@pathname") 2>&1`; + $ret = "$backupcmd \"@pathname\""; } + Log 2, "Backup with command: $cmd"; + $ret = `($cmd) 2>&1`; + if($ret) { chomp $ret; Log 1, "backup $ret"; diff --git a/fhem/FHEM/98_telnet.pm b/fhem/FHEM/98_telnet.pm index c80acb118..ff37aef41 100644 --- a/fhem/FHEM/98_telnet.pm +++ b/fhem/FHEM/98_telnet.pm @@ -22,6 +22,10 @@ telnet_Initialize($) $hash->{NotifyFn}= "telnet_SecurityCheck"; $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 globalpassword password ". "allowfrom SSL connectTimeout connectInterval"; + $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 globalpassword password ". + "allowfrom SSL connectTimeout connectInterval"; + $hash->{ActivateInformFn} = "telnet_ActivateInform"; + } ##################################### @@ -292,6 +296,15 @@ telnet_Undef($$) return TcpServer_Close($hash); } +sub +telnet_ActivateInform($) +{ + my ($cl) = @_; + my $name = $cl->{NAME}; + CommandInform($cl, "timer") if(!$inform{$name}); +} + + 1; =pod diff --git a/fhem/FHEM/98_update.pm b/fhem/FHEM/98_update.pm index 7f7beda7b..77b4b2e8d 100644 --- a/fhem/FHEM/98_update.pm +++ b/fhem/FHEM/98_update.pm @@ -27,6 +27,7 @@ use strict; use warnings; use HttpUtils; use File::Copy qw(cp mv); +use Blocking; sub CommandUpdate($$); sub update_CheckFhemRelease($$$); @@ -192,19 +193,61 @@ CommandUpdate($$) ($notice,$unconfirmed) = update_CheckNotice($BRANCH,$update,"before"); $ret .= $notice if(defined($notice)); return $ret if($unconfirmed); - $ret .= update_DoUpdate($srcdir,$BRANCH,$update,$force,$cl); - ($notice,$unconfirmed) = update_CheckNotice($BRANCH,$update,"after"); - $ret .= $notice if(defined($notice)); - my $sendStatistics = AttrVal("global","sendStatistics",undef); - if(defined($sendStatistics) && lc($sendStatistics) eq "onupdate") { - $ret .= "\n\n"; - $ret .= AnalyzeCommandChain(undef, "fheminfo send"); + + if(AttrVal("global","updateInBackground",undef)) { + CallFn($cl->{NAME}, "ActivateInformFn", $cl); + BlockingCall("update_DoUpdateInBackground", {srcdir=>$srcdir, + BRANCH=>$BRANCH, update=>$update, force=>$force,cl=>$cl}); + $ret = "Executing the update the background."; + + } else { + $ret .= update_DoUpdate($srcdir,$BRANCH,$update,$force,$cl); + ($notice,$unconfirmed) = update_CheckNotice($BRANCH,$update,"after"); + $ret .= $notice if(defined($notice)); + my $sendStatistics = AttrVal("global","sendStatistics",undef); + if(defined($sendStatistics) && lc($sendStatistics) eq "onupdate") { + $ret .= "\n\n"; + $ret .= AnalyzeCommandChain(undef, "fheminfo send"); + } } + } return $ret; } +my $inLog = 0; +sub +update_Log2Event($$) +{ + my ($level, $text) = @_; + return if($inLog || $level > $attr{global}{verbose}); + $inLog = 1; + BlockingInformParent("DoTrigger", ["global", $text, 1], 0); + BlockingInformParent("Log", [$level, $text], 0); + $inLog = 0; +} + +sub +update_DoUpdateInBackground($) +{ + my ($h) = @_; + + no warnings 'redefine'; # The main process is not affected + *Log = \&update_Log2Event; + sleep(2); # Give time for ActivateInform / FHEMWEB / JavaScript + + my $ret = update_DoUpdate($h->{srcdir}, $h->{BRANCH}, $h->{update}, + $h->{force}, $h->{cl}); + my ($notice,$unconfirmed) = + update_CheckNotice($h->{BRANCH}, $h->{update}, "after"); + $ret .= $notice if(defined($notice)); + if(lc(AttrVal("global","sendStatistics","")) eq "onupdate") { + $ret .= "\n\n"; + $ret .= AnalyzeCommandChain(undef, "fheminfo send"); + } +} + ######################################## sub update_CheckNotice($$$) diff --git a/fhem/FHEM/Blocking.pm b/fhem/FHEM/Blocking.pm index ac45b7719..4af86d151 100644 --- a/fhem/FHEM/Blocking.pm +++ b/fhem/FHEM/Blocking.pm @@ -22,6 +22,7 @@ sub BlockingKill($); sub BlockingInformParent($;$$); my $telnetDevice; +my $telnetClient; sub BlockingCall($$@) @@ -102,30 +103,36 @@ BlockingInformParent($;$$) $waitForRead = 1 if (!defined($waitForRead)); # Write the data back, calling the function - my $addr = "localhost:$defs{$telnetDevice}{PORT}"; - my $client = IO::Socket::INET->new(PeerAddr => $addr); - Log 1, "CallBlockingFn: Can't connect to $addr\n" if(!$client); - - if (defined($param)) { - $param =~ s/'/\\'/g; - $param = "'$param'" - } else { - $param = ""; + if(!$telnetClient) { + my $addr = "localhost:$defs{$telnetDevice}{PORT}"; + $telnetClient = IO::Socket::INET->new(PeerAddr => $addr); + Log 1, "CallBlockingFn: Can't connect to $addr\n" if(!$telnetClient); } - syswrite($client, "{$informFn($param)}\n"); + if(defined($param)) { + if(ref($param) eq "ARRAY") { + $param = join(",", map { $_ =~ s/'/\\'/g; "'$_'" } @{$param}); + + } else { + $param =~ s/'/\\'/g; + $param = "'$param'" + } + } else { + $param = ""; + } + + syswrite($telnetClient, "{$informFn($param)}\n"); if ($waitForRead) { - my $len = sysread($client, $ret, 4096); + my $len = sysread($telnetClient, $ret, 4096); chop($ret); $ret = undef if(!defined($len)); } - close($client) if($client); - return $ret; } +# Parent sub BlockingKill($) { @@ -148,9 +155,11 @@ BlockingKill($) } } +# Child sub BlockingExit() { + close($telnetClient) if($telnetClient); if($^O =~ m/Win/) { eval "require threads;"; diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html index 2b24b5513..0637d8c1a 100644 --- a/fhem/docs/commandref_frame.html +++ b/fhem/docs/commandref_frame.html @@ -982,6 +982,13 @@ A line ending with \ will be concatenated with the next one, so long lines receiving a corresponding message.
+ +
  • updateInBackground
    + If this attribute is set to 1, the update will be executed in the + backgrund process. The return message is communicated via events, and + in telnet the inform command is activated, in FHEMWEB the Event + Monitor. +

  • backup_before_update
    diff --git a/fhem/docs/commandref_frame_DE.html b/fhem/docs/commandref_frame_DE.html index 1768ea926..c1b07bbaa 100644 --- a/fhem/docs/commandref_frame_DE.html +++ b/fhem/docs/commandref_frame_DE.html @@ -1019,12 +1019,20 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.

  • autoload_undefined_devices
    - wenn dieses Attribut gesetzt ist, werden die zu einer neu empfangenen - Nachricht zugehörigen Module automatisch geladen.  Dies erfolgt vom - autocreate Gerät, um so automatisch ein FHEM-Gerät bei erreichen - einer entsprechenden Nachricht zu erstellen. + wenn dieses Attribut gesetzt ist, werden die zu einer neu empfangenen + Nachricht zugehörigen Module automatisch geladen.  Dies + erfolgt vom autocreate Gerät, um so + automatisch ein FHEM-Gerät bei erreichen einer entsprechenden + Nachricht zu erstellen.

  • + +
  • updateInBackground
    + wenn dieses Attribut gesetzt ist, wird das update Befehl in einem + separaten Prozess ausgeführt, und alle Meldungen werden per Event + übermittelt. In der telnet Sitzung wird inform, in FHEMWEB wird + das Event Monitor aktiviert. +

  • backup_before_update
    diff --git a/fhem/fhem.pl b/fhem/fhem.pl index 6ea5ba520..877ed68c5 100755 --- a/fhem/fhem.pl +++ b/fhem/fhem.pl @@ -167,6 +167,7 @@ use vars qw(%data); # Hash for user data use vars qw($devcount); # To sort the devices use vars qw(%defaultattr); # Default attributes, used by FHEM2FHEM use vars qw(%addNotifyCB); # Used by event enhancers (e.g. avarage) +use vars qw(%inform); # Used by telnet_ActivateInform use vars qw($reread_active); @@ -177,7 +178,6 @@ my $ipv6; # Using IPV6 my $currlogfile; # logfile, without wildcards my $currcfgfile=""; # current config/include file my $logopened = 0; # logfile opened or using stdout -my %inform; # Inform hash my $rcvdquit; # Used for quit handling in init files my $sig_term = 0; # if set to 1, terminate (saving the state) my %intAt; # Internal at timer hash. @@ -207,7 +207,7 @@ $modules{Global}{AttrList} = "autoload_undefined_devices:1,0 dupTimeout latitude longitude " . "backupcmd backupdir backupsymlink backup_before_update " . "exclude_from_update motd updatebranch uniqueID ". - "sendStatistics:onUpdate,manually,never ". + "sendStatistics:onUpdate,manually,never updateInBackground:1,0". "showInternalValues:1,0 "; $modules{Global}{AttrFn} = "GlobalAttr"; diff --git a/fhem/www/pgm2/console.js b/fhem/www/pgm2/console.js index ccf3a2459..7a491e6e4 100644 --- a/fhem/www/pgm2/console.js +++ b/fhem/www/pgm2/console.js @@ -1,5 +1,7 @@ var consConn; +var isFF = (navigator.userAgent.toLowerCase().indexOf('firefox') > -1); + function consUpdate() { @@ -15,8 +17,16 @@ consUpdate() return; var el = document.getElementById("console"); - if(el) + if(el) { el.innerHTML="Events:
    "+consConn.responseText; + // Scroll to bottom. FF is different from Safari/Chrome + var p = el.parentElement; // content div + if(isFF) + p.parentElement.parentElement.scrollTop = p.scrollHeight; // html tag + else + p.parentElement.scrollTop = p.scrollHeight; // body tag + console.log("P4:"+p.scrollHeight); + } } function