diff --git a/fhem/FHEM/10_MQTT2_DEVICE.pm b/fhem/FHEM/10_MQTT2_DEVICE.pm index fa1cba3ff..9ae0d8277 100644 --- a/fhem/FHEM/10_MQTT2_DEVICE.pm +++ b/fhem/FHEM/10_MQTT2_DEVICE.pm @@ -26,9 +26,11 @@ MQTT2_DEVICE_Initialize($) autocreate:0,1 bridgeRegexp:textField-long devicetopic + devPos disable:0,1 disabledForIntervals getList:textField-long + imageLink jsonMap:textField-long model readingList:textField-long @@ -290,6 +292,7 @@ MQTT2_DEVICE_Set($@) my ($sets,$cmdList) = MQTT2_getCmdHash(AttrVal($hash->{NAME}, "setList", "")); my $cmdName = $a[1]; + return MQTT2_DEVICE_addPos($hash,@a) if($cmdName eq "addPos"); # hidden cmd my $cmd = $sets->{$cmdName}; return SetExtensions($hash, $cmdList, @a) if(!$cmd); return undef if(IsDisabled($hash->{NAME})); @@ -459,24 +462,37 @@ MQTT2_DEVICE_fhemwebFn($$$$) { my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn. - return if(!ReadingsVal($d, ".graphviz", ReadingsVal($d, "graphviz", ""))); - - my $js = "$FW_ME/pgm2/zwave_neighborlist.js"; - - return - "
Show neighbor map
". - "
". - "". - ' + if(ReadingsVal($d, ".graphviz", ReadingsVal($d, "graphviz", ""))) { + my $js = "$FW_ME/pgm2/zwave_neighborlist.js"; + return + "
Show neighbor map
". + "
". + "". + ' JSEND + } + + my $img = AttrVal($d, "imageLink", ""); + if($img) { + return + "
". + "". + "
". + ' +JSEND + } } sub @@ -484,17 +500,54 @@ MQTT2_DEVICE_nlData($) { my ($d) = @_; - my %h; + my (%dv,%h,%n2n); my $fo=""; + my $pref = "https://koenkk.github.io/zigbee2mqtt/images/devices/"; + + # Needed for the image links + my $dv = ReadingsVal($d, ".devices", ReadingsVal($d, "devices", "")); + for my $l (split(/[\r\n]/, $dv)) { + next if($l !~ m/ieeeAddr":"([^"]+)".*model":"([^"]+)"/); + $dv{$1} = $2; + } + + # Name translation + for my $n (devspec2array("TYPE=MQTT2_DEVICE")) { + my $cid = $defs{$n}{CID}; + next if(!$cid); + $cid =~ s/zigbee_//; + $n2n{$cid} = $n; + } + my $gv = ReadingsVal($d, ".graphviz", ReadingsVal($d, "graphviz", "")); for my $l (split(/[\r\n]/, $gv)) { + if($l =~ m/^\s*"([^"]+)"\s*\[label="([^"]+)"\]/) { my ($n,$v) = ($1,$2); - $v =~ s/[{}]//; - $v =~ s/\|/
/g; my $nv = $n; $nv =~ s/^0x0*//; + $h{$n}{img} = ''; + + if($v =~ m/{(.*)\|(.*)\|(.*)\|(.*)}/) { + my ($x1,$x2,$x3,$x4) = ($1,$2,$3,$4); + $nv = $n2n{$x1} if($n2n{$x1}); + $h{$n}{img} = $pref.$dv{$n}.".jpg" if($dv{$n}); + if($dv{$n} && $n2n{$x1} && !AttrVal($n2n{$x1}, "imageLink", "")) { + CommandAttr(undef, "$nv imageLink $h{$n}{img}"); + } + $h{$n}{class} = ($x2 =~ m/Coordinator|Router/ ? "zwDongle":"zwBox"); + if($x2 =~ m/Coordinator/) { + $nv = $d; + $fo = $n; + } + } else { + $h{$n}{class}="zwBox"; + } + + $v =~ s/[{}]//; + $v =~ s/\|/
/g; $h{$n}{txt} = $nv; + $h{$n}{title} = $v; $fo = $n if(!$fo); my @a; @@ -504,20 +557,39 @@ MQTT2_DEVICE_nlData($) push @{$h{$1}{neighbors}}, $2; } } + my @ret; + my @dp = split(" ", AttrVal($d, "devPos", "")); + my %dp = @dp; + for my $k (keys %h) { my $n = $h{$k}{neighbors}; push @ret, '"'.$k.'":{'. - '"class":"zwBox col_link col_oddrow",'. + '"class":"'.$h{$k}{class}.' col_link col_oddrow",'. + '"img":"'.$h{$k}{img}.'",'. '"txt":"'.$h{$k}{txt}.'",'. '"title":"'.$h{$k}{title}.'",'. - '"pos":[],'. + '"pos":['.($dp{$k} ? $dp{$k} : '').'],'. '"neighbors":['. (@{$n} ? ('"'.join('","',@{$n}).'"'):'').']}'; } - return '{"firstObj":"'.$fo.'","el":{'.join(",",@ret).'} }'; + my $r = '{"firstObj":"'.$fo.'","el":{'.join(",",@ret).'},'. + '"saveFn":"set '.$d.' addPos {1} {2}" }'; + return $r; } +sub +MQTT2_DEVICE_addPos($@) +{ + my ($hash, @a) = @_; + my @d = split(" ", AttrVal($a[0], "devPos", "")); + my %d = @d; + $d{$a[2]} = $a[3]; + CommandAttr(undef,"$a[0] devPos ".join(" ", map {"$_ $d{$_}"} sort keys %d)); +} +# graphvis end +##################################### + ##################################### # Utility functions for the AttrTemplates sub @@ -625,6 +697,13 @@ zigbee2mqtt_devStateIcon255($) name of the device.
+ +
  • devPos value
    + used internally by the "Show neighbor map" visualizer in FHEMWEB. + This function is active if the graphviz and devices readings are set, + usually in the zigbee2mqtt bridge device. +

  • +
  • disable
    disabledForIntervals

  • @@ -658,6 +737,12 @@ zigbee2mqtt_devStateIcon255($)
    + +
  • imageLink href
    + sets the image to be shown. The "Show neighbor map" function initializes + the value automatically. +
  • +
  • jsonMap oldReading1:newReading1 oldReading2:newReading2...
    space or newline separated list of oldReading:newReading pairs.
    diff --git a/fhem/www/pgm2/zwave_neighborlist.js b/fhem/www/pgm2/zwave_neighborlist.js index 1a769313b..e6d17b427 100644 --- a/fhem/www/pgm2/zwave_neighborlist.js +++ b/fhem/www/pgm2/zwave_neighborlist.js @@ -61,6 +61,8 @@ zw_nl(fhemFn) var el = fnRet.el[eName]; if(el.pos[0] != el.x || el.pos[1] != el.y) { log("SavePos:"+eName); + el.x = Math.round(el.x*100)/100; + el.y = Math.round(el.y*100)/100; el.pos[0] = el.x; el.pos[1] = el.y; var cmd = sprintf(fnRet.saveFn, eName, el.x+","+el.y); FW_cmd(FW_root+"?cmd="+cmd+"&XHR=1");