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"
+
+
+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"
+
+
+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;