diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html
index bfe7cdca8..0b25e40de 100644
--- a/fhem/docs/commandref_frame.html
+++ b/fhem/docs/commandref_frame.html
@@ -436,6 +436,24 @@ Device specific attributes are documented in the corresponding device section.
attr store eventMap /on-for-timer 10:open/off:closed/
set store open
+ The explicit variant of this attribute has the following syntax:
+
+ attr store eventMap { dev=>{"on"=>"open"}, usr=>{"open"=>"on"} }
+ attr store eventMap { dev=>{"^on(-for-timer)?(.*)"=>"open$2"},
+ usr=>{"^open(.*)"=>"on$1"},
+ fw=>{"^open(.*)"=>"open"} }
+
+ This variant must be used, if the mapping is not symmetrical, the first
+ part (dev) representing the device to user mapping, i.e. if the device
+ reports on 100 or on-for-timer 100, the user will see open 100. The
+ second part (usr) is the other direction, if the user specified open
+ 10, the device will receive on 10. On both occasions the key will be
+ first compared directly with the text, and if it is not equal, then it
+ will be tried to match it as a regexp. When using regexps in the usr
+ part with wildcards, the fw part must be filled with the exact same
+ keys to enable a correct display in the FHEMWEB set dropdown list in
+ the detail view.
+
diff --git a/fhem/docs/commandref_frame_DE.html b/fhem/docs/commandref_frame_DE.html
index 3f85dcffb..e61f40638 100644
--- a/fhem/docs/commandref_frame_DE.html
+++ b/fhem/docs/commandref_frame_DE.html
@@ -453,6 +453,25 @@ Gerät dokumentiert.
attr store eventMap /on-for-timer 10:open/off:closed/
set store open
+ Die explizite Variante dieses Attributes hat folgenden Syntax:
+
+ attr store eventMap { dev=>{"on"=>"open"}, usr=>{"open"=>"on"} }
+ attr store eventMap { dev=>{"^on(-for-timer)?(.*)"=>"open$2"},
+ usr=>{"^open(.*)"=>"on$1"},
+ fw=>{"^open(.*)"=>"open"} }
+
+ Diese Variante muss dann verwendet werden, falls das Mapping nicht
+ symmetrisch ist. Der erste Teil (dev) spezifiziert dabei die Richtung
+ Gerät zu Benutzer, d.h. falls das Gerät on 100 oder
+ on-for-timer 100 meldet, dann wird der Benutzer open 100 zu sehen
+ bekommen. Der zweite Teil (usr) spezifiziert die Richtung Benutzer zu
+ Gerät, d.h. wenn man "set XX open 100" eingibt, dann wird das
+ Kommando "on 100" an das Gerät gesendet. In beiden Fällen wird
+ der Schlüssel zuerst direkt, und dann als Regexp mit dem Wert
+ verglichen. Falls man Regexps mit Wildcards im usr Teil verwendet, dann
+ muss man den fw Teil mit dem exakt gleichen Schlüsseln
+ ausfüllen, damit FHEMWEB in der Detail-Ansicht den set-Auswahl
+ richtig anzeigen kann.
@@ -1211,7 +1230,7 @@ Die folgenden lokalen Attribute werden von mehreren Geräten verwendet:
setstate <devspec> <value>
- Der Befehl setzt den STATE Eintrag des Ger&aauml;tes direkt, ohne Ereignisse
+ Der Befehl setzt den STATE Eintrag des Gerätes direkt, ohne Ereignisse
zu generieren oder ein Signal an das Gerät zu senden. Dieser Eintrag ist
maßgebend für die Status-Anzeige in diversen Frontends. Dieser
Befehl wird auch im statefile benutzt.
Siehe den
diff --git a/fhem/fhem.pl b/fhem/fhem.pl
index 56c08440f..5ba3bb84c 100755
--- a/fhem/fhem.pl
+++ b/fhem/fhem.pl
@@ -2202,17 +2202,7 @@ getAllSets($)
$a2 = "" if($a2 =~ /^No set implemented for/);
return "" if($a2 eq "");
- my $em = AttrVal($d, "eventMap", undef);
- if($em) {
- # Delete the first word of the translation (.*:), else it will be
- # interpreted as the single possible value for a dropdown
- # Why is the .*= deleted?
- $em = join(" ", grep { !/ / }
- map { $_ =~ s/.*?=//s;
- $_ =~ s/.*?://s; $_ }
- attrSplit($em));
- $a2 = "$em $a2";
- }
+ $a2 = $defs{$d}{".eventMapCmd"}." $a2" if(defined($defs{$d}{".eventMapCmd"}));
return $a2;
}
@@ -2370,6 +2360,17 @@ CommandAttr($$)
next;
}
+ if($attrName eq "eventMap") {
+ delete $hash->{".eventMapHash"};
+ delete $hash->{".eventMapCmd"};
+ $attr{$sdev}{eventMap} = (defined $a[2] ? $a[2] : 1);
+ my $r = ReplaceEventMap($sdev, "test", 1); # refresh eventMapCmd
+ if($r =~ m/^ERROR in eventMap for /) {
+ delete($attr{$sdev}{eventMap});
+ return $r;
+ }
+ }
+
$a[0] = $sdev;
my $oVal = ($attr{$sdev} ? $attr{$sdev}{$attrName} : "");
$ret = CallFn($sdev, "AttrFn", "set", @a);
@@ -3345,24 +3346,37 @@ attrSplit($)
}
#######################
-# $dir: 0 = User to Fhem (i.e. set), 1 = Fhem to User (i.e trigger)
+# $dir: 0: User to Device (i.e. set) 1: Device to Usr (i.e trigger)
+# $dir: 0: $str is an array pointer 1: $str is a a string
sub
ReplaceEventMap($$$)
{
my ($dev, $str, $dir) = @_;
my $em = $attr{$dev}{eventMap};
+
return $str if($dir && !$em);
return @{$str} if(!$dir && (!$em || int(@{$str}) < 2 || $str->[1] eq "?"));
- my $dname = shift @{$str} if(!$dir);
- my $nstr = join(" ", @{$str}) if(!$dir);
- my $changed;
+ return ReplaceEventMap2($dev, $str, $dir, $em) if($em =~ m/^{.*}$/);
my @emList = attrSplit($em);
+
+ if(!defined $defs{$dev}{".eventMapCmd"}) {
+ # Delete the first word of the translation (.*:), else it will be
+ # interpreted as the single possible value for a dropdown
+ # Why is the .*= deleted?
+ $defs{$dev}{".eventMapCmd"} = join(" ", grep { !/ / }
+ map { $_ =~ s/.*?=//s; $_ =~ s/.*?://s; "$_:noArg" } @emList);
+ }
+
+ my $dname = shift @{$str} if(!$dir);
+ my $nstr = join(" ", @{$str}) if(!$dir);
+
+ my $changed;
foreach my $rv (@emList) {
# Real-Event-Regexp:GivenName[:modifier]
my ($re, $val, $modifier) = split(":", $rv, 3);
next if(!defined($val));
- if($dir) { # event -> GivenName
+ if($dir) { # dev -> usr
my $reIsWord = ($re =~ m/^\w*$/); # dim100% is not \w only, cant use \b
if($reIsWord) {
if($str =~ m/\b$re\b/) {
@@ -3376,7 +3390,7 @@ ReplaceEventMap($$$)
}
}
- } else { # GivenName -> set command
+ } else { # usr -> dev
if($nstr eq $val) { # for special translations like <> and <<
$nstr = $re;
$changed = 1;
@@ -3408,6 +3422,68 @@ ReplaceEventMap($$$)
}
}
+# $dir: 0:usr,$str is array pointer, 1:dev, $str is string
+# perl notation: { dev=>{"re1"=>"Evt1",...}, dpy=>{"re2"=>"Set 1",...}}
+sub
+ReplaceEventMap2($$$)
+{
+ my ($dev, $str, $dir) = @_;
+
+ my $hash = $defs{$dev};
+ my $emh = $hash->{".eventMapHash"};
+ if(!$emh) {
+ eval "\$emh = $attr{$dev}{eventMap}";
+ if($@) {
+ my $msg = "ERROR in eventMap for $dev: $@";
+ Log 1, $msg;
+ return $msg;
+ }
+ $hash->{".eventMapHash"} = $emh;
+
+ $defs{$dev}{".eventMapCmd"} = "";
+ if($emh->{usr}) {
+ my @cmd;
+ my $fw = $emh->{fw};
+ $defs{$dev}{".eventMapCmd"} = join(" ",
+ map { ($fw && $fw->{$_}) ? $fw->{$_}:$_} sort keys %{$emh->{usr} });
+ }
+ }
+
+ if($dir == 1) {
+ $emh = $emh->{dev};
+ if($emh) {
+ foreach my $k (keys %{$emh}) {
+ return $emh->{$k} if($str eq $k);
+ return eval '"'.$emh->{$k}.'"' if($str =~ m/$k/);
+ }
+ }
+ return $str;
+ }
+
+ $emh = $emh->{usr};
+ return @{$str} if(!$emh);
+
+ my $dname = shift @{$str};
+ my $nstr = join(" ", @{$str});
+ foreach my $k (keys %{$emh}) {
+ my $nv;
+ if($nstr eq $k) {
+ $nv = $emh->{$k};
+
+ } elsif($nstr =~ m/$k/) {
+ $nv = eval '"'.$emh->{$k}.'"';
+
+ }
+ if($nv) {
+ my @arr = split(" ",$nv);
+ unshift @arr, $dname;
+ return @arr;
+ }
+ }
+ unshift @{$str}, $dname;
+ return @{$str};
+}
+
sub
setGlobalAttrBeforeFork($)
{