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
- a single device name. This is the most common case.
- a list of devices, separated by comma (,)
- - a range of devices, separated by dash (-)
- - a regular expression, if the the spec contains on e of the following
- characters: ^*[]$
- - 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.
+ - a regular expression
+ - 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
+ - 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.
- Example:
+ Examples:
set lamp1 on
set lamp1,lamp2,lamp3 on
- set lamp[1-3] on
set lamp.* on
- set lamp1-lamp3 on
- set lamp1-lamp3,lamp3 on
set room=kitchen off
+ set room=kitchen:FILTER=STATE=on off
+ set room=kitchen:FILTER=STATE!=off off
list disabled=
- list TYPE=FS20
+ list TYPE=FS20 STATE
Notes:
- - first the spec is separated by komma, then the range or the regular
- expression operations are executed.
+ - the spec may not contain space characters.
- if there is a device which exactly corresponds to the spec, then
no special processing is done.
+ - first the spec is separated by komma, then the regular expression and
+ filter operations are executed.
- the returned list can contain the same device more than once, so
- "set lamp1-lamp3,lamp3 on" switches lamp3 twice.
+ "set lamp3,lamp3 on" switches lamp3 twice.
- for more complex structuring demands see the
structure device.
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.
Geräte-Spezifikation (devspec)
- Befehle wie
+ Die Befehle
attr,
set,
get, usw.
+ attr,
+ deleteattr,
+ displayattr,
+ delete,
+ get,
+ list,
+ set,
+ setreading,
+ setstate,
+ trigger
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:
- - ein einzelner Gerätename. Dies ist der
- meist vorkommende Fall.
- -
- eine Liste von Gerätenamen, durch Kommata (,) getrennt
- -
- ein Bereich, durch ein Minuszeichen getrennt (-)
- - ein regulärer Ausdruck der eines der
- folgenden Zeichen enthält: ^*[]$
- -
- 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.
+ - ein einzelner Gerätename. Dies ist der Normalfall
+ - eine durch Komma(,) getrennte Liste von Gerätenamen
+ - ein regulärer Ausdruck
+ - 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.
+
+ - Falls die Spezifikation von :FILTER=NAME=WERT gefolgt wird,
+ dann wird die zuvor gefundene Liste durch diesen neuen Ausdruck
+ gefiltert.
Beispiele:
set lamp1 on
set lamp1,lamp2,lamp3 on
- set lamp[1-3] on
set lamp.* on
- set lamp1-lamp3 on
- set lamp1-lamp3,lamp3 on
set room=kitchen off
+ set room=kitchen:FILTER=STATE=on off
+ set room=kitchen:FILTER=STATE!=off off
list disabled=
- list TYPE=FS20
+ list TYPE=FS20 STATE
Bemerkungen:
- - zuerst wird die durch Kommata getrennte
- Spezifikation abgearbeitet, dann folgen die Bereichsspezifikationen und die
- regulären Ausdrücke
- -
- wenn für ein Gerät eine Spezifikation exakt zutrifft, werden keine weiteren
- Vergleiche vorgenommen.
- -
- die Befehlszeile kann die selbe Gerätebezeichnung mehrfach enthalten z.B.: "set
- lamp1-lamp3, lamp3 on".
- Lamp3 wird hier zwei Mal eingeschalten.
- - um Strukturen mit komplexeren Anforderungen zu realisieren lesen Sie bitte
- den Abschnitt zu
- structure.
-
+ - die Spezifikation kann keine Leerzeichen enthalten.
+ - falls ein Gerätename exakt dem Spezifikation entspricht, dann werden
+ keine reguläre Ausdrücke oder Filter ausgewertet.
+
- zuerst wird die durch Komma getrennte Spezifikation abgearbeitet, dann
+ folgen die regulären Ausdrücke und die Filter
+ - die Befehlszeile kann die selbe Gerätebezeichnung mehrfach enthalten
+ z.B.: "set lamp3,lamp3 on". Lamp3 wird hier zwei Mal
+ eingeschalten.
+ - um Strukturen mit komplexeren Anforderungen zu realisieren lesen Sie
+ bitte den Abschnitt zu structure.
+
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;
}