From 211c4e09ea7513802f35c5f2c1fabdb23cb4abf6 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Sat, 7 Dec 2013 11:31:38 +0000 Subject: [PATCH] fhem.pl/devspec: removed range, added :=FILTER=, the = operator is more general git-svn-id: https://svn.fhem.de/fhem/trunk@4333 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/docs/commandref_frame.html | 29 ++++++------ fhem/docs/commandref_frame_DE.html | 69 +++++++++++++++-------------- fhem/fhem.pl | 71 ++++++++++++------------------ 4 files changed, 78 insertions(+), 92 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 292241967..3c207a007 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,6 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. - SVN + - feature: devspec: removed range, added :FILTER and more general search - feature: HUEBridge,HUEDevice: support for groups added - feature: YAMAHA_AVR: new argument "toggle" for mute command - feature: FB_CALLMONITOR: replace & to & at reverse search diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html index e2239f1dd..796b4b341 100644 --- a/fhem/docs/commandref_frame.html +++ b/fhem/docs/commandref_frame.html @@ -279,34 +279,33 @@ A line ending with \ will be concatenated with the next one, so long lines <ul> <li>a single device name. This is the most common case.</li> <li>a list of devices, separated by comma (,)</li> - <li>a range of devices, separated by dash (-)</li> - <li>a regular expression, if the the spec contains on e of the following - characters: ^*[]$</li> - <li>an attribute of the device, followed by an equal sign (=) and then a - regexp for this attribute. As attribute you can specify either attributes - set with the attr command or one of the "internal" attributes DEF, STATE - and TYPE.</li> + <li>a regular expression</li> + <li>a NAME=VALUE pair, where NAME can be an Internal value like TYPE, a + Reading-Name or an attribute. VALUE is a regexp. To negate the + comparison, use NAME!=VALUE</li> + <li>if the spec is followed by the expression :FILTER=NAME=VALUE, then the + values found in the first round are filtered by the second expression. </ul> - Example: + Examples: <ul> <code>set lamp1 on</code><br> <code>set lamp1,lamp2,lamp3 on</code><br> - <code>set lamp[1-3] on</code><br> <code>set lamp.* on</code><br> - <code>set lamp1-lamp3 on</code><br> - <code>set lamp1-lamp3,lamp3 on</code><br> <code>set room=kitchen off</code><br> + <code>set room=kitchen:FILTER=STATE=on off</code><br> + <code>set room=kitchen:FILTER=STATE!=off off</code><br> <code>list disabled=</code><br> - <code>list TYPE=FS20</code><br> + <code>list TYPE=FS20 STATE</code><br> </ul> Notes: <ul> - <li>first the spec is separated by komma, then the range or the regular - expression operations are executed.</li> + <li>the spec may not contain space characters.</n> <li>if there is a device which exactly corresponds to the spec, then no special processing is done.</li> + <li>first the spec is separated by komma, then the regular expression and + filter operations are executed.</li> <li>the returned list can contain the same device more than once, so - "set lamp1-lamp3,lamp3 on" switches lamp3 twice.</li> + "set lamp3,lamp3 on" switches lamp3 twice.</li> <li>for more complex structuring demands see the <a href="#structure"> structure</a> device. </ul> diff --git a/fhem/docs/commandref_frame_DE.html b/fhem/docs/commandref_frame_DE.html index d61c4aa33..4b202cc53 100644 --- a/fhem/docs/commandref_frame_DE.html +++ b/fhem/docs/commandref_frame_DE.html @@ -265,56 +265,59 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.</p> <a name="devspec"></a> <h3>Geräte-Spezifikation (devspec)</h3> <ul> - Befehle wie + Die Befehle <a href="#attr">attr</a>, <a href="#set">set</a>, <a href="#get">get</a>, usw. + <a href="#attr">attr</a>, + <a href="#deleteattr">deleteattr</a>, + <a href="#displayattr">displayattr</a>, + <a href="#delete">delete</a>, + <a href="#get">get</a>, + <a href="#list">list</a>, + <a href="#set">set</a>, + <a href="#setreading">setreading</a>, + <a href="#setstate">setstate</a>, + <a href="#trigger">trigger</a> können eine komplexere Gerätespezifikation als Argumente enthalten, die auch eine Anzahl von Geräten betreffen kann. Eine - Gerätespezifikation (Kurzfassung) kann z.B. so aussehen: + Gerätespezifikation kann folgendes sein: <ul> - <li>ein einzelner Gerätename. Dies ist der - meist vorkommende Fall.</li> - <li> - eine Liste von Gerätenamen, durch Kommata (,) getrennt</li> - <li> - ein Bereich, durch ein Minuszeichen getrennt (-)</li> - <li>ein regulärer Ausdruck der eines der - folgenden Zeichen enthält: ^*[]$</li> - <li> - ein Geräteattribut, gefolgt von einem Gleichheitszeichen (=) und einem - regulären Ausdruck für dieses Attribut. - Als Attribut können Sie entweder Attribute die mittels "attr"-Befehl oder - eines der "internen" Attribute wie DEF, STATE oder TYPE angeben.</li> + <li>ein einzelner Gerätename. Dies ist der Normalfall</li> + <li>eine durch Komma(,) getrennte Liste von Gerätenamen</li> + <li>ein regulärer Ausdruck</li> + <li>ein NAME=WERT Ausdruck, wo NAME ein "Internal" Wert wie TYPE ist, ein + Reading-Name oder ein Attribut. WERT ist ein regulärer Ausdruck. + Um die Bedingung zu negieren, sollte NAME!=WERT verwendet werden. + </li> + <li>Falls die Spezifikation von :FILTER=NAME=WERT gefolgt wird, + dann wird die zuvor gefundene Liste durch diesen neuen Ausdruck + gefiltert. </ul> Beispiele: <ul> <code>set lamp1 on</code><br> <code>set lamp1,lamp2,lamp3 on</code><br> - <code>set lamp[1-3] on</code><br> <code>set lamp.* on</code><br> - <code>set lamp1-lamp3 on</code><br> - <code>set lamp1-lamp3,lamp3 on</code><br> <code>set room=kitchen off</code><br> + <code>set room=kitchen:FILTER=STATE=on off</code><br> + <code>set room=kitchen:FILTER=STATE!=off off</code><br> <code>list disabled=</code><br> - <code>list TYPE=FS20</code><br> + <code>list TYPE=FS20 STATE</code><br> </ul> Bemerkungen: <ul> - <li>zuerst wird die durch Kommata getrennte - Spezifikation abgearbeitet, dann folgen die Bereichsspezifikationen und die - regulären Ausdrücke</li> - <li> - wenn für ein Gerät eine Spezifikation exakt zutrifft, werden keine weiteren - Vergleiche vorgenommen.</li> - <li> - die Befehlszeile kann die selbe Gerätebezeichnung mehrfach enthalten z.B.: "set - lamp1-lamp3, lamp3 on". - Lamp3 wird hier zwei Mal eingeschalten.</li> - <li>um Strukturen mit komplexeren Anforderungen zu realisieren lesen Sie bitte - den Abschnitt zu <a href="#structure"> - structure</a>. - </li></ul> + <li>die Spezifikation kann keine Leerzeichen enthalten.</li> + <li>falls ein Gerätename exakt dem Spezifikation entspricht, dann werden + keine reguläre Ausdrücke oder Filter ausgewertet. + <li>zuerst wird die durch Komma getrennte Spezifikation abgearbeitet, dann + folgen die regulären Ausdrücke und die Filter</li> + <li>die Befehlszeile kann die selbe Gerätebezeichnung mehrfach enthalten + z.B.: "set lamp3,lamp3 on". Lamp3 wird hier zwei Mal + eingeschalten.</li> + <li>um Strukturen mit komplexeren Anforderungen zu realisieren lesen Sie + bitte den Abschnitt zu <a href="#structure"> structure</a>. + </ul> </ul> <a name="help"></a> diff --git a/fhem/fhem.pl b/fhem/fhem.pl index 77950f34a..da0f7142c 100755 --- a/fhem/fhem.pl +++ b/fhem/fhem.pl @@ -862,8 +862,6 @@ AnalyzeCommand($$) sub devspec2array($) { - my %knownattr = ( "DEF"=>1, "STATE"=>1, "TYPE"=>1 ); - my ($name) = @_; return "" if(!defined($name)); @@ -872,59 +870,44 @@ devspec2array($) return "FHEM2FHEM_FAKE_$name" if($defs{$name}{FAKEDEVICE}); return $name; } - # FAKE is set by FHEM2FHEM LOG - my ($isattr, @ret); + my @ret; + foreach my $l (split(",", $name)) { # List of elements + my @names = sort keys %defs; + my @res; + foreach my $dName (split(":FILTER=", $name)) { + my ($n,$op,$re) = ("NAME","=",$dName); + ($n,$op,$re) = ($1,$2,$3) if($dName =~ m/^([^!]*)(=|!=)(.*)$/); - foreach my $l (split(",", $name)) { # List - - if($l =~ m/(.*)=(.*)/) { - my ($lattr,$re) = ($1, $2); - if($knownattr{$lattr}) { - eval { # a bad regexp may shut down fhem.pl - foreach my $l (sort keys %defs) { - push @ret, $l - if($defs{$l}{$lattr} && (!$re || $defs{$l}{$lattr}=~m/^$re$/)); + @res=(); + foreach my $d (@names) { + next if($attr{$d} && $attr{$d}{ignore}); + my $hash = $defs{$d}; + my $val = $hash->{$n}; + if(!defined($val)) { + my $r = $hash->{READINGS}; + $val = $r->{$n}{VAL} if($r && $r->{$n}); + } + if(!defined($val)) { + $val = $attr{$d}{$n} if($attr{$d}); + } + next if(!defined($val)); + eval { # a bad regexp is deadly + if(($op eq "=" && $val =~ m/^$re$/) || + ($op eq "!=" && $val !~ m/^$re$/)) { + push @res, $d } }; if($@) { Log 1, "devspec2array $name: $@"; return $name; } - } else { - foreach my $l (sort keys %attr) { - push @ret, $l - if($attr{$l}{$lattr} && (!$re || $attr{$l}{$lattr} =~ m/$re/)); - } } - $isattr = 1; - next; + @names = @res; } - - my $regok; - eval { # a bad regexp may shut down fhem.pl - if($l =~ m/[*\[\]^\$]/) { # Regexp - push @ret, grep($_ =~ m/^$l$/, sort keys %defs); - $regok = 1; - } - }; - if($@) { - Log 1, "devspec2array $name: $@"; - return $name; - } - next if($regok); - - if($l =~ m/-/) { # Range - my ($lower, $upper) = split("-", $l, 2); - push @ret, grep($_ ge $lower && $_ le $upper, sort keys %defs); - next; - } - push @ret, $l; + push @ret,@res; } - - return $name if(!@ret && !$isattr); # No match, return the input - @ret = grep { !$attr{$_} || !$attr{$_}{ignore} } @ret - if($name !~ m/^ignore=/); + return $name if(!@ret); return @ret; }