diff --git a/fhem/CHANGED b/fhem/CHANGED
index a46830036..74b42402d 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: readingsGroup: added icons and links/commands
- feature: new module 98_Text2Speech.pm added (Tobias Faust)
Google Translator Engine or ESpeak can be used
- feature: YAMAHA_AVR: define separate on and off status intervals for
diff --git a/fhem/FHEM/33_readingsGroup.pm b/fhem/FHEM/33_readingsGroup.pm
index 03a3f3294..fc4b2b18a 100644
--- a/fhem/FHEM/33_readingsGroup.pm
+++ b/fhem/FHEM/33_readingsGroup.pm
@@ -35,7 +35,7 @@ sub readingsGroup_Initialize($)
#$hash->{SetFn} = "readingsGroup_Set";
$hash->{GetFn} = "readingsGroup_Get";
$hash->{AttrFn} = "readingsGroup_Attr";
- $hash->{AttrList} = "disable:1,2,3 nameIcon valueIcon mapping separator style nameStyle valueColumns valueStyle valueFormat timestampStyle noheading:1 nolinks:1 notime:1 nostate:1 alwaysTrigger:1";
+ $hash->{AttrList} = "disable:1,2,3 nameIcon valueIcon mapping separator style nameStyle valueColumns valueStyle valueFormat commands timestampStyle noheading:1 nolinks:1 notime:1 nostate:1 alwaysTrigger:1";
$hash->{FW_detailFn} = "readingsGroup_detailFn";
$hash->{FW_summaryFn} = "readingsGroup_detailFn";
@@ -165,6 +165,7 @@ lookup($$$$$$$$)
$default = $mapping->{$name} if( defined($mapping->{$name}) );
$default = $mapping->{$reading} if( defined($mapping->{$reading}) );
$default = $mapping->{$name.".".$reading} if( defined($mapping->{$name.".".$reading}) );
+ $default = $mapping->{$reading.".".$value} if( defined($mapping->{$reading.".".$value}) );
#} elsif( $mapping =~ m/^{.*}$/) {
# my $DEVICE = $name;
# my $READING = $reading;
@@ -203,6 +204,7 @@ lookup2($$$$)
my $vf = "";
$vf = $lookup->{$reading} if( exists($lookup->{$reading}) );
$vf = $lookup->{$name.".".$reading} if( exists($lookup->{$name.".".$reading}) );
+ $vf = $lookup->{$reading.".".$value} if( exists($lookup->{$reading.".".$value}) );
$lookup = $vf;
} elsif($lookup =~ m/^{.*}$/) {
my $DEVICE = $name;
@@ -212,8 +214,44 @@ lookup2($$$$)
$lookup = "" if( $@ );
}
+ $lookup =~ s/\%DEVICE/$name/g;
+ $lookup =~ s/\%READING/$reading/g;
+ $lookup =~ s/\%VALUE/$value/g;
+
+ $lookup =~ s/\$DEVICE/$name/g;
+ $lookup =~ s/\$READING/$reading/g;
+ $lookup =~ s/\$VALUE/$value/g;
+
return $lookup;
}
+sub
+readingsGroup_makeLink($$$)
+{
+ my($v,$devStateIcon,$cmd) = @_;
+
+ if( $cmd ) {
+ my $txt = $v;
+ $txt = $devStateIcon if( $devStateIcon );
+ my $link = "cmd=$cmd";
+ if( AttrVal($FW_wname, "longpoll", 1)) {
+ $txt = "$txt";
+ } else {
+ my $room = $FW_webArgs{room};
+ $room = "&detail=$FW_webArgs{detail}";
+ my $srf = $room ? "&room=$room" : "";
+ $srf = $room if( $room && $room =~ m/^&/ );
+ $txt = "$txt";
+ }
+ if( !$devStateIcon ) {
+ $v = $txt;
+ } else {
+ $devStateIcon = $txt;
+ }
+ }
+
+ return ($v, $devStateIcon);
+}
+
sub
readingsGroup_2html($)
{
@@ -284,6 +322,8 @@ readingsGroup_2html($)
$valueIcon = eval $valueIcon if( $valueIcon =~ m/^{.*}$/ );
#$valueIcon = undef if( ref($valueIcon) ne 'HASH' );
+ my $commands = AttrVal( $d, "commands", "" );
+ $commands = eval $commands if( $commands =~ m/^{.*}$/ );
my $devices = $hash->{DEVICES};
@@ -320,6 +360,7 @@ readingsGroup_2html($)
if( $regex && $regex =~ m/^<(.*)>$/ ) {
my $txt = $1;
my $readings;
+ $item++;
if( $txt =~ m/^{(.*)}(@[\w|.*]+)?$/ ) {
$txt = "{$1}";
$readings = $2;
@@ -342,6 +383,14 @@ readingsGroup_2html($)
$ret .= "
| ";
$first = 0;
next;
+ } elsif( $txt && $txt =~ m/^%([^%]*)(%(.*))?/ ) {
+ my $icon = $1;
+ my $cmd = $3;
+ $txt = FW_makeImage( $icon, $icon, "icon" );
+
+ $cmd = lookup2($commands,$name,undef,$icon) if( !defined($cmd) );
+ ($txt,undef) = readingsGroup_makeLink($txt,undef,$cmd);
+
} elsif( $first || $multi == 1 ) {
$ret .= sprintf("", ($row&1)?"odd":"even");
$row++;
@@ -357,10 +406,9 @@ readingsGroup_2html($)
$ret .= "$txt | ";
}
}
- $item++;
my $inform_id = "";
$inform_id = "informId=\"$d-$item.item\"" if( $readings );
- $ret .= "$txt | ";
+ $ret .= "$txt | ";
$first = 0;
next;
} elsif( $regex && $regex =~ m/^\+(.*)/ ) {
@@ -422,6 +470,7 @@ readingsGroup_2html($)
}
}
+ my $cmd;
my $devStateIcon;
if( $valueIcon ) {
if( my $icon = lookup($valueIcon,$name,$a,$n,$v,$room,$group,"") ) {
@@ -431,10 +480,15 @@ readingsGroup_2html($)
$devStateIcon = $txt;
} else {
$devStateIcon = FW_makeImage( $icon, $v, "icon" );
+ $cmd = lookup2($commands,$name,$n,$icon);
+ $cmd = lookup2($commands,$name,$n,$v) if( !$cmd );
}
}
}
+ $cmd = lookup2($commands,$name,$n,$v) if( !$devStateIcon );
+ ($v,$devStateIcon) = readingsGroup_makeLink($v,$devStateIcon,$cmd);
+
if( $first || $multi == 1 ) {
$ret .= sprintf("
", ($row&1)?"odd":"even");
$row++;
@@ -580,6 +634,10 @@ readingsGroup_Notify($$)
my $valueIcon = AttrVal( $name, "valueIcon", "");
$valueIcon = eval $valueIcon if( $valueIcon =~ m/^{.*}$/ );
+ my $commands = AttrVal( $name, "commands", "" );
+ $commands = eval $commands if( $commands =~ m/^{.*}$/ );
+
+
foreach my $device (@{$devices}) {
my $item = 0;
my $h = $defs{@{$device}[0]};
@@ -600,6 +658,7 @@ readingsGroup_Notify($$)
if( $regex && $regex =~ m/^<(.*)>$/ ) {
my $txt = $1;
my $readings;
+ $item++;
if( $txt =~ m/^{(.*)}(@([\w|.*]+))?$/ ) {
$txt = "{$1}";
$readings = $3;
@@ -616,7 +675,14 @@ readingsGroup_Notify($$)
}
$txt = "" if( !defined($txt) );
- $item++;
+ if( $txt && $txt =~ m/^%([^%]*)(%(.*))?/ ) {
+ my $icon = $1;
+ my $cmd = $3;
+
+ $txt = FW_makeImage( $icon, $icon, "icon" );
+ ($txt,undef) = readingsGroup_makeLink($txt,undef,$cmd);
+ }
+
CommandTrigger( "", "$name $item.item: $txt" );
}
@@ -640,6 +706,7 @@ readingsGroup_Notify($$)
}
}
+ my $cmd;
my $devStateIcon;
if( $valueIcon ) {
my $n = $h->{NAME};
@@ -653,13 +720,22 @@ readingsGroup_Notify($$)
$devStateIcon = $txt;
} else {
$devStateIcon = FW_makeImage( $icon, $value, "icon" );
+ $cmd = lookup2($commands,$n,$reading,$icon);
+ $cmd = lookup2($commands,$n,$reading,$value) if( !$cmd );
}
}
- CommandTrigger( "", "$name $n.$reading: $devStateIcon" ) if( $devStateIcon );
- next if( $devStateIcon );
+ if( $devStateIcon ) {
+ (undef,$devStateIcon) = readingsGroup_makeLink(undef,$devStateIcon,$cmd);
+
+ CommandTrigger( "", "$name $n.$reading: $devStateIcon" );
+ next;
+ }
}
+ $cmd = lookup2($commands,$dev->{NAME},$reading,$value);
+ ($value,undef) = readingsGroup_makeLink($value,undef,$cmd);
+
$value = "$value
" if( $value_style );
CommandTrigger( "", "$name $dev->{NAME}.$reading: $value" );
@@ -759,8 +835,12 @@ readingsGroup_Attr($$$)
If regex starts with a '+' it will be matched against the internal values of the device instead of the readings.
If regex starts with a '?' it will be matched against the attributes of the device instead of the readings.
regex can be of the form <STRING> or <{perl}[@readings]> where STRING or the string returned by perl is
- inserted as the reading. skipped if STRING is undef. if STRING is br a new line will be started. if readings is
- given the perl expression will be reevaluated during longpoll updates.
+ inserted as a reading or:
+ - the item will be skipped if STRING is undef
+ - if STRING is br a new line will be started
+ - if STRING is of the form %ICON[%CMD] ICON will be used as the name of an icon instead of a text and CMD
+ as the command to be executed if the icon is clicked. also see the commands attribute.
+ if readings is given the perl expression will be reevaluated during longpoll updates.
For internal values and attributes longpoll update is not possible. Refresh the page to update the values.
the <{perl}> expression is limited to expressions without a space. it is best just to call a small sub
in 99_myUtils.pm instead of having a compex expression in the define.
@@ -793,6 +873,19 @@ readingsGroup_Attr($$$)
attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}
attr Verbrauch valueIcon { state => '%devStateIcon' }
attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 150)?'style="color:red"':'style="color:green"'}
+
+ define rg_battery readingsGroup TYPE=LaCrosse:[Bb]attery
+ attr rg_battery alias Batteriestatus
+ attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }
+ attr rg_battery valueFormat {($VALUE eq 'ok')?"batterie":"batterie\@red"}
+ attr rg_battery valueIcon %VALUE
+
+ define rgMediaPlayer readingsGroup myMediaPlayer:currentTitle,<>,totaltime,
,currentAlbum,<>,currentArtist,
,volume,<{if(ReadingsVal($DEVICE,"playStatus","")eq"paused"){"%rc_PLAY%set+$DEVICE+play"}else{"%rc_PAUSE%set+$DEVICE+pause"}}@playStatus>,playStatus
+ attr rgMediaPlayer commands { "playStatus.paused" => "set %DEVICE play", "playStatus.playing" => "set %DEVICE pause" }
+ attr rgMediaPlayer mapping
+ attr rgMediaPlayer notime 1
+ attr rgMediaPlayer valueFormat { "volume" => "Volume: %i" }
+ #attr rgMediaPlayer valueIcon { "playStatus.paused" => "rc_PLAY", "playStatus.playing" => "rc_PAUSE" }
@@ -863,7 +956,11 @@ readingsGroup_Attr($$$)
in {} that returns a hash that maps reading value to the icon name. e.g.:
attr devices valueIcon $VALUE
attr devices valueIcon {state => '%VALUE'}
- attr devices valueIcon {state => '%devStateIcon'}
+ attr devices valueIcon {state => '%devStateIcon'}
+ attr rgMediaPlayer valueIcon { "playStatus.paused" => "rc_PLAY", "playStatus.playing" => "rc_PAUSE" }
+ commands
+ Makes a reading or icon clickable and specifies the command that should be executed. eg.:
+ attr rgMediaPlayer commands { "playStatus.paused" => "set %DEVICE play", "playStatus.playing" => "set %DEVICE pause" }
The nameStyle and valueStyle attributes can also contain a perl expression enclosed in {} that returns the style