From ff078b9f9be32ed0c0a183f13c29c739488a98f8 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Sun, 10 Apr 2022 11:34:15 +0000 Subject: [PATCH] MQTT2_CLIENT/MQTT2_SERVER: add "Show MQTT traffic" git-svn-id: https://svn.fhem.de/fhem/trunk@25943 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/00_MQTT2_CLIENT.pm | 66 ++++++++++++++++++++++++++++++++- fhem/FHEM/00_MQTT2_SERVER.pm | 57 ++++++++++++++++++++++++++++ fhem/FHEM/01_FHEMWEB.pm | 9 +++-- fhem/www/pgm2/console.js | 72 ++++++++++++++++++++++++++++++------ 4 files changed, 188 insertions(+), 16 deletions(-) diff --git a/fhem/FHEM/00_MQTT2_CLIENT.pm b/fhem/FHEM/00_MQTT2_CLIENT.pm index ab2bc0cee..1a4964d28 100644 --- a/fhem/FHEM/00_MQTT2_CLIENT.pm +++ b/fhem/FHEM/00_MQTT2_CLIENT.pm @@ -12,6 +12,8 @@ sub MQTT2_CLIENT_Undef($@); sub MQTT2_CLIENT_doPublish($@); sub MQTT2_CLIENT_Disco($;$$); +use vars qw(%FW_id2inform); + # See also: # http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html @@ -57,6 +59,7 @@ MQTT2_CLIENT_Initialize($) ); use warnings 'qw'; $hash->{AttrList} = join(" ", @attrList)." ".$readingFnAttributes; + $hash->{FW_detailFn} = "MQTT2_CLIENT_fhemwebFn"; } sub @@ -536,6 +539,7 @@ MQTT2_CLIENT_Read($@) DoTrigger($name, "$tp:$val") if($re && $tp =~ m/$re/); } } + MQTT2_CLIENT_feedTheList($hash, $tp, $val, 1); } else { Log 1, "M2: Unhandled packet $cpt, disconneting $name"; @@ -592,7 +596,8 @@ MQTT2_CLIENT_doPublish($@) length($pi)). pack("n", length($topic)). $topic.$pi.$val; - MQTT2_CLIENT_send($hash, $msg, $immediate) + MQTT2_CLIENT_send($hash, $msg, $immediate); + MQTT2_CLIENT_feedTheList($hash, $topic, $val); } sub @@ -687,6 +692,65 @@ MQTT2_CLIENT_getStr($$) return ($r, $off+2+$l); } +sub +MQTT2_CLIENT_fhemwebFn() +{ + my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn. + + return '' if($pageHash); + + return << "JSEND" +
Show MQTT traffic
+ +JSEND +} + +sub +MQTT2_CLIENT_addToFeedList($$) +{ + my ($name, $turnOn) = @_; + my $hash = $defs{$name}; + return if(!$hash); + + my $fwid = $FW_chash->{FW_ID}; + $hash->{".feedList"} = () if(!$hash->{".feedList"}); + if($turnOn) { + $hash->{".feedList"}{$fwid} = 1; + + } else { + delete($hash->{".feedList"}{$fwid}); + delete($hash->{".feedList"}) if(!keys %{$hash->{".feedList"}}); + } + return undef; +} + +sub +MQTT2_CLIENT_feedTheList($$$) +{ + my ($server, $tp, $val, $cid) = @_; + my $fl = $server->{".feedList"}; + if($fl) { + foreach my $fwid (keys %{$fl}) { + my $cl = $FW_id2inform{$fwid}; + if(!$cl || !$cl->{inform}{filter} || $cl->{inform}{filter} ne '^$') { + delete($fl->{$fwid}); + next; + } + FW_AsyncOutput($cl, "", + defined($cid) ? "RCVD: $tp $val
" : "SENT: $tp $val
"); + } + delete($server->{".feedList"}) if(!keys %{$fl}); + } +} 1; =pod diff --git a/fhem/FHEM/00_MQTT2_SERVER.pm b/fhem/FHEM/00_MQTT2_SERVER.pm index 334258fbe..c12a7bb3f 100644 --- a/fhem/FHEM/00_MQTT2_SERVER.pm +++ b/fhem/FHEM/00_MQTT2_SERVER.pm @@ -12,6 +12,7 @@ sub MQTT2_SERVER_Write($$$); sub MQTT2_SERVER_Undef($@); sub MQTT2_SERVER_doPublish($$$$;$); +use vars qw(%FW_id2inform); # See also: # http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html @@ -50,6 +51,7 @@ MQTT2_SERVER_Initialize($) ); use warnings 'qw'; $hash->{AttrList} = join(" ", @attrList)." ".$readingFnAttributes; + $hash->{FW_detailFn} = "MQTT2_SERVER_fhemwebFn"; } sub @@ -564,6 +566,20 @@ MQTT2_SERVER_doPublish($$$$;$) my $re = AttrVal($serverName, "rawEvents", undef); DoTrigger($server->{NAME}, "$tp:$val") if($re && $tp =~ m/$re/); } + + my $fl = $server->{".feedList"}; + if($fl) { + foreach my $fwid (keys %{$fl}) { + my $cl = $FW_id2inform{$fwid}; + if(!$cl || !$cl->{inform}{filter} || $cl->{inform}{filter} ne '^$') { + delete($fl->{$fwid}); + next; + } + FW_AsyncOutput($cl, "", + defined($cid) ? "RCVD: $tp $val
" : "SENT: $tp $val
"); + } + delete($server->{".feedList"}) if(!keys %{$fl}); + } } ###################################### @@ -665,6 +681,47 @@ MQTT2_SERVER_getStr($$$) return ($r, $off+2+$l); } +sub +MQTT2_SERVER_fhemwebFn() +{ + my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn. + + return '' if($pageHash); + + return << "JSEND" +
Show MQTT traffic
+ +JSEND +} + +sub +MQTT2_SERVER_addToFeedList($$) +{ + my ($name, $turnOn) = @_; + my $hash = $defs{$name}; + return if(!$hash); + + my $fwid = $FW_chash->{FW_ID}; + $hash->{".feedList"} = () if(!$hash->{".feedList"}); + if($turnOn) { + $hash->{".feedList"}{$fwid} = 1; + + } else { + delete($hash->{".feedList"}{$fwid}); + delete($hash->{".feedList"}) if(!keys %{$hash->{".feedList"}}); + } + return undef; +} + # {MQTT2_SERVER_ReadDebug("m2s", '0(12)(0)(5)HelloWorld')} sub MQTT2_SERVER_ReadDebug($$) diff --git a/fhem/FHEM/01_FHEMWEB.pm b/fhem/FHEM/01_FHEMWEB.pm index 9bf070c39..b4779c518 100644 --- a/fhem/FHEM/01_FHEMWEB.pm +++ b/fhem/FHEM/01_FHEMWEB.pm @@ -92,6 +92,7 @@ use vars qw(@FW_httpheader); # HTTP header, line by line use vars qw(%FW_httpheader); # HTTP header, as hash use vars qw($FW_userAgent); # user agent string use vars qw($FW_addJs); # Only for helper like AttrTemplate +use vars qw(%FW_id2inform); $FW_formmethod = "post"; @@ -101,7 +102,6 @@ my $FW_lastWebName = ""; # Name of last FHEMWEB instance, for caching my $FW_lastHashUpdate = 0; my $FW_httpRetCode = ""; my %FW_csrfTokenCache; -my %FW_id2inform; ######################### # As we are _not_ multithreaded, it is safe to use global variables. @@ -360,7 +360,7 @@ FW_Read($$) my $buf; my $ret = sysread($c, $buf, 1024); $buf = Encode::decode($hash->{encoding}, $buf) - if($unicodeEncoding && $hash->{encoding}); + if($unicodeEncoding && $hash->{encoding} && !$hash->{websocket}); if(!defined($ret) && $! == EWOULDBLOCK ){ $hash->{wantWrite} = 1 @@ -750,9 +750,9 @@ FW_addToWritebuffer($$@) } sub -FW_AsyncOutput($$) +FW_AsyncOutput($$;$) { - my ($hash, $ret) = @_; + my ($hash, $ret, $directData) = @_; return if(!$hash || !$hash->{FW_ID}); if( $ret =~ m/^(.*)<\/html>$/s ) { @@ -766,6 +766,7 @@ FW_AsyncOutput($$) my $data = FW_longpollInfo('JSON', "#FHEMWEB:$FW_wname","FW_okDialog('$ret')",""); + $data = $directData if($directData); # find the longpoll connection with the same fw_id as the page that was the # origin of the get command diff --git a/fhem/www/pgm2/console.js b/fhem/www/pgm2/console.js index 636ac0d4a..5c9a32041 100644 --- a/fhem/www/pgm2/console.js +++ b/fhem/www/pgm2/console.js @@ -2,7 +2,7 @@ FW_version["console.js"] = "$Id$"; var consConn; -var debug; +var consName="#console"; var consFilter, oldFilter, consFType=""; var consLastIndex = 0; @@ -77,14 +77,14 @@ consUpdate(evt) return ""; }); - var isTa = $("#console").is("textarea"); // 102773 + var isTa = $(consName).is("textarea"); // 102773 var ncA = new_content.split(/
[\r\n]/); for(var i1=0; i1 ]/g, function(a){return rTab[a]}); - $("#console").append(logContent+ncA.join(isTa?"\n":"
")); + $(consName).append(logContent+ncA.join(isTa?"\n":"
")); if(mustScroll) - $("#console").scrollTop($("#console")[0].scrollHeight); + $(consName).scrollTop($(consName)[0].scrollHeight); } function @@ -98,6 +98,7 @@ consFill() var query = "?XHR=1"+ "&inform=type=raw;withLog="+withLog+";filter="+ encodeURIComponent(consFilter)+consFType+ + "&fw_id="+$("body").attr('fw_id')+ "×tamp="+new Date().getTime(); query = addcsrf(query); @@ -129,7 +130,7 @@ consFill() consLastIndex = 0; if(oldFilter != consFilter) // only clear, when filter changes - $("#console").html(""); + $(consName).html(""); oldFilter = consFilter; } @@ -137,9 +138,11 @@ consFill() function consStart() { - var el = document.getElementById("console"); + if($(consName).length != 1) + return; - consFilter = $("a#eventFilter").html(); + if($("a#eventFilter").length) + consFilter = $("a#eventFilter").html(); if(consFilter == undefined) consFilter = ".*"; oldFilter = consFilter; @@ -148,7 +151,7 @@ consStart() $("#eventReset").click(function(evt){ // Event Monitor Reset log("Console resetted by user"); - $("#console").html(""); + $(consName).html(""); }); $("#eventFilter").click(function(evt){ // Event-Filter Dialog @@ -192,10 +195,10 @@ consStart() }); - $("#console").scroll(function() { // autoscroll check + $(consName).scroll(function() { // autoscroll check - if($("#console")[0].scrollHeight - $("#console").scrollTop() <= - $("#console").outerHeight() + 2) { + if($(consName)[0].scrollHeight - $(consName).scrollTop() <= + $(consName).outerHeight() + 2) { if(!mustScroll) { mustScroll = 1; log("Console autoscroll restarted"); @@ -337,4 +340,51 @@ consAddRegexpPart() }); } +function +cons4dev(screenId, filter, feedFn, devName) +{ + $(screenId).find("a") + .blur() // remove focus, so return wont open/close it + .unbind("click") + .click(toggleOpen); + + consName = screenId+">div.console"; + consFilter = filter; + var opened; + + function + toggleOpen() + { + $(this).blur(); + var cmd = FW_root+"?cmd="+encodeURIComponent("{"+feedFn+"('"+devName+"',"+ + (opened ? 0 : 1)+")}")+"&XHR=1"; + if(!opened) { + $(screenId).append('
'); + $(consName) + .width( $("#content").width()-40) + .height($("#content").height()/2-20) + .css({overflow:"auto"}); + $(screenId+">a").html($(screenId+">a").html().replace("Show", "Hide")); + FW_closeConn(); + consStart(); + // Leave time for establishing the connection, else the "feeder" may + // clear the flag + setTimeout(function(){ FW_cmd(cmd) }, 100); + + } else { + FW_cmd(cmd); + $(consName).remove(); + $(screenId+">a").html($(screenId+">a").html().replace("Hide", "Show")); + if(consConn) { + consConn.onclose = undefined; + cons_closeConn(); + } + FW_longpoll(); + } + opened = !opened; + } + + toggleOpen(); +} + window.onload = consStart;