# $Id$ package main; use strict; use warnings; use vars qw(%FW_webArgs); # all arguments specified in the GET sub readingsGroup_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "readingsGroup_Define"; $hash->{NotifyFn} = "readingsGroup_Notify"; $hash->{UndefFn} = "readingsGroup_Undefine"; #$hash->{SetFn} = "readingsGroup_Set"; $hash->{GetFn} = "readingsGroup_Get"; $hash->{AttrList} = "nameIcons mapping separator style nameStyle valueStyle valueFormat timestampStyle noheading:1 nolinks:1 notime:1 nostate:1"; $hash->{FW_detailFn} = "readingsGroup_detailFn"; $hash->{FW_summaryFn} = "readingsGroup_detailFn"; $hash->{FW_atPageEnd} = 1; } sub readingsGroup_updateDevices($) { my ($hash) = @_; my %list; my @devices; my @params = split(" ", $hash->{DEF}); while (@params) { my $param = shift(@params); # for backwards compatibility with weblink readings if( $param eq '*noheading' ) { $attr{$hash->{NAME}}{noheading} = 1; $hash->{DEF} =~ s/(\s*)\\$param((:\S+)?\s*)/ /g; $hash->{DEF} =~ s/^ //; $hash->{DEF} =~ s/ $//; } elsif( $param eq '*notime' ) { $attr{$hash->{NAME}}{notime} = 1; $hash->{DEF} =~ s/(\s*)\\$param((:\S+)?\s*)/ /g; $hash->{DEF} =~ s/^ //; $hash->{DEF} =~ s/ $//; } elsif( $param eq '*nostate' ) { $attr{$hash->{NAME}}{nostate} = 1; $hash->{DEF} =~ s/(\s*)\\$param((:\S+)?\s*)/ /g; $hash->{DEF} =~ s/^ //; $hash->{DEF} =~ s/ $//; } elsif( $param =~ m/^{/) { $attr{$hash->{NAME}}{mapping} = $param ." ". join( " ", @params ); $hash->{DEF} =~ s/\s*[{].*$//g; last; } else { my @device = split(":", $param); if($device[0] =~ m/(.*)=(.*)/) { my ($lattr,$re) = ($1, $2); foreach my $d (sort keys %defs) { next if( IsIgnored($d) ); next if( !defined($defs{$d}{$lattr}) ); next if( $defs{$d}{$lattr} !~ m/^$re$/); $list{$d} = 1; push @devices, [$d,$device[1]]; } } elsif( defined($defs{$device[0]}) ) { $list{$device[0]} = 1; push @devices, [@device]; } else { foreach my $d (sort keys %defs) { next if( IsIgnored($d) ); next if( $d !~ m/^$device[0]$/); $list{$d} = 1; push @devices, [$d,$device[1]]; } } } } $hash->{CONTENT} = \%list; $hash->{DEVICES} = \@devices; } sub readingsGroup_Define($$) { my ($hash, $def) = @_; my @args = split("[ \t]+", $def); return "Usage: define readingsGroup +" if(@args < 3); my $name = shift(@args); my $type = shift(@args); readingsGroup_updateDevices($hash); $hash->{STATE} = 'Initialized'; return undef; } sub readingsGroup_Undefine($$) { my ($hash,$arg) = @_; return undef; } sub lookup($$$$$) { my($mapping,$name,$alias,$reading,$default) = @_; if( $mapping ) { if( ref($mapping) eq 'HASH' ) { $default = $mapping->{$name} if( defined($mapping) && defined($mapping->{$name}) ); $default = $mapping->{$reading} if( defined($mapping) && defined($mapping->{$reading}) ); $default = $mapping->{$name.".".$reading} if( defined($mapping) && defined($mapping->{$name.".".$reading}) ); } else { $default = $mapping; } $default =~ s/\%ALIAS/$alias/g; $default =~ s/\%DEVICE/$name/g; $default =~ s/\%READING/$reading/g; $default =~ s/\$ALIAS/$alias/g; $default =~ s/\$DEVICE/$name/g; $default =~ s/\$READING/$reading/g; } return $default; } sub readingsGroup_2html($) { my($hash) = @_; $hash = $defs{$hash} if( ref($hash) ne 'HASH' ); return undef if( !$hash ); my $d = $hash->{NAME}; my $show_heading = !AttrVal( $d, "noheading", "0" ); my $show_links = !AttrVal( $d, "nolinks", "0" ); my $show_state = !AttrVal( $d, "nostate", "0" ); my $show_time = !AttrVal( $d, "notime", "0" ); my $separator = AttrVal( $d, "separator", ":" ); my $style = AttrVal( $d, "style", "" ); my $name_style = AttrVal( $d, "nameStyle", "" ); my $value_style = AttrVal( $d, "valueStyle", "" ); my $timestamp_style = AttrVal( $d, "timestampStyle", "" ); my $value_format = AttrVal( $d, "valueFormat", "" ); if( $value_format =~ m/^{.*}$/ ) { my $vf = eval $value_format; $value_format = $vf if( $vf ); } my $mapping = AttrVal( $d, "mapping", ""); $mapping = eval $mapping if( $mapping =~ m/^{.*}$/ ); #$mapping = undef if( ref($mapping) ne 'HASH' ); my $nameIcons = AttrVal( $d, "nameIcons", ""); $nameIcons = eval $nameIcons if( $nameIcons =~ m/^{.*}$/ ); #$nameIcons = undef if( ref($nameIcons) ne 'HASH' ); my $devices = $hash->{DEVICES}; my $ret; my $row = 1; $ret .= ""; my $txt = AttrVal($d, "alias", $d); $txt = "$txt" if( $show_links ); $ret .= "" if( $show_heading ); $ret .= ""; $ret .= "
$txt
"; foreach my $device (@{$devices}) { my $h = $defs{@{$device}[0]}; my $regex = @{$device}[1]; my $name = $h->{NAME}; next if( !$h ); if( $regex && $regex =~ m/\+(.*)/ ) { $regex = $1; my $now = gettimeofday(); my $fmtDateTime = FmtDateTime($now); foreach my $n (sort keys %{$h}) { next if( $n =~ m/^\./); next if( defined($regex) && $n !~ m/^$regex$/); my $val = $h->{$n}; my $r = ref($val); next if($r && ($r ne "HASH" || !defined($hash->{$n}{VAL}))); my $v = FW_htmlEscape($val); my $name_style = $name_style; if(defined($name_style) && $name_style =~ m/^{.*}$/) { my $DEVICE = $name; my $READING = $n; my $VALUE = $v; $name_style = eval $name_style; $name_style = "" if( !$name_style ); } my $value_style = $value_style; if(defined($value_style) && $value_style =~ m/^{.*}$/) { my $DEVICE = $name; my $READING = $n; my $VALUE = $v; $value_style = eval $value_style; $value_style = "" if( !$value_style ); } if( $value_format ) { my $value_format = $value_format; if( ref($value_format) eq 'HASH' ) { my $vf; $vf = $value_format->{$n} if( defined($value_format->{$n}) ); $vf = $value_format->{$name.".".$n} if( defined($value_format->{$name.".".$n}) ); $value_format = $vf; } elsif( $value_format =~ m/^{.*}$/) { my $DEVICE = $name; my $READING = $n; my $VALUE = $v; $value_format = eval $value_format; } next if( !defined($value_format) ); $v = sprintf( $value_format, $v ) if( $value_format ); } my $a = AttrVal($name, "alias", $name); my $m = "$a$separator$n"; my $txt = lookup($mapping,$name,$a,$n,$m); if( $nameIcons ) { if( my $icon = lookup($nameIcons,$name,$a,$n,"") ) { $txt = FW_makeImage( $icon, $txt, "icon" ); } } $ret .= sprintf("", ($row&1)?"odd":"even"); $row++; $txt = "$txt" if( $show_links ); $ret .= ""; $ret .= ""; $ret .= "" if( $show_time ); } } else { foreach my $n (sort keys %{$h->{READINGS}}) { next if( $n =~ m/^\./); next if( $n eq "state" && !$show_state ); next if( defined($regex) && $n !~ m/^$regex$/); my $val = $h->{READINGS}->{$n}; if(ref($val)) { my ($v, $t) = ($val->{VAL}, $val->{TIME}); $v = FW_htmlEscape($v); $t = "" if(!$t); my $name_style = $name_style; if(defined($name_style) && $name_style =~ m/^{.*}$/) { my $DEVICE = $name; my $READING = $n; my $VALUE = $v; $name_style = eval $name_style; $name_style = "" if( !$name_style ); } my $value_style = $value_style; if(defined($value_style) && $value_style =~ m/^{.*}$/) { my $DEVICE = $name; my $READING = $n; my $VALUE = $v; $value_style = eval $value_style; $value_style = "" if( !$value_style ); } if( $value_format ) { my $value_format = $value_format; if( ref($value_format) eq 'HASH' ) { my $vf; $vf = $value_format->{$n} if( defined($value_format->{$n}) ); $vf = $value_format->{$name.".".$n} if( defined($value_format->{$name.".".$n}) ); $value_format = $vf; } elsif( $value_format =~ m/^{.*}$/) { my $DEVICE = $name; my $READING = $n; my $VALUE = $v; $value_format = eval $value_format; } next if( !defined($value_format) ); $v = sprintf( $value_format, $v ) if( $value_format ); } my $a = AttrVal($name, "alias", $name); my $m = "$a$separator$n"; my $txt = lookup($mapping,$name,$a,$n,$m); if( $nameIcons ) { if( my $icon = lookup($nameIcons,$name,$a,$n,"") ) { $txt = FW_makeImage( $icon, $txt, "icon" ); } } $ret .= sprintf("", ($row&1)?"odd":"even"); $row++; $txt = "$txt" if( $show_links ); $ret .= ""; $ret .= ""; $ret .= "" if( $show_time ); } } } } $ret .= "
$txt
$v
$fmtDateTime
$txt
$v
$t
"; #$ret .= "
"; return $ret; } sub readingsGroup_detailFn() { my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn. return readingsGroup_2html($d); } sub readingsGroup_Notify($$) { my ($hash,$dev) = @_; my $name = $hash->{NAME}; if( grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}) ) { readingsGroup_updateDevices($hash); return undef; } elsif( grep(m/^REREADCFG$/, @{$dev->{CHANGED}}) ) { readingsGroup_updateDevices($hash); return undef; } return if($dev->{NAME} eq $name); my $devices = $hash->{DEVICES}; my $max = int(@{$dev->{CHANGED}}); for (my $i = 0; $i < $max; $i++) { my $s = $dev->{CHANGED}[$i]; $s = "" if(!defined($s)); if( $dev->{NAME} eq "global" && $s =~ m/^RENAMED ([^ ]*) ([^ ]*)$/) { my ($old, $new) = ($1, $2); if( defined($hash->{CONTENT}{$old}) ) { $hash->{DEF} =~ s/(\s*)$old((:\S+)?\s*)/$1$new$2/g; } readingsGroup_updateDevices($hash); } elsif( $dev->{NAME} eq "global" && $s =~ m/^DELETED ([^ ]*)$/) { my ($name) = ($1); if( defined($hash->{CONTENT}{$name}) ) { $hash->{DEF} =~ s/(\s*)$name((:\S+)?\s*)/ /g; $hash->{DEF} =~ s/^ //; $hash->{DEF} =~ s/ $//; } readingsGroup_updateDevices($hash); } elsif( $dev->{NAME} eq "global" && $s =~ m/^DEFINED ([^ ]*)$/) { readingsGroup_updateDevices($hash); } else { next if(AttrVal($name,"disable", undef)); next if (!$hash->{CONTENT}->{$dev->{NAME}}); my @parts = split(/: /,$s); my $reading = shift @parts; my $value = join(": ", @parts); $reading = "" if( !defined($reading) ); next if( $reading =~ m/^\./); $value = "" if( !defined($value) ); if( $value eq "" ) { next if( AttrVal( $name, "nostate", "0" ) ); $reading = "state"; $value = $s; } my $value_format = AttrVal( $name, "valueFormat", "" ); if( $value_format =~ m/^{.*}$/ ) { my $vf = eval $value_format; $value_format = $vf if( $vf ); } foreach my $device (@{$devices}) { my $h = $defs{@{$device}[0]}; next if( !$h ); next if( $dev->{NAME} ne $h->{NAME} ); my $regex = @{$device}[1]; next if( defined($regex) && $reading !~ m/^$regex$/); if( $value_format ) { my $value_format = $value_format; if( ref($value_format) eq 'HASH' ) { my $vf; $vf = $value_format->{$reading} if( defined($value_format->{$reading}) ); $vf = $value_format->{$dev->{NAME}.".".$reading} if( defined($value_format->{$dev->{NAME}.".".$reading}) ); $value_format = $vf; } elsif( $value_format =~ m/^{.*}$/) { my $DEVICE = $dev->{NAME}; my $READING = $reading; my $VALUE = $value; $value_format = eval $value_format; } $value = sprintf( $value_format, $value ) if( $value_format ); } CommandTrigger( "", "$name $dev->{NAME}.$reading: $value" ); } } } return undef; } sub readingsGroup_Set($@) { my ($hash, $name, $cmd, $param, @a) = @_; my $list = "refresh:noArgs"; if( $cmd eq "refresh" ) { readingsGroup_updateDevices($hash); return undef; } return "Unknown argument $cmd, choose one of $list"; } sub readingsGroup_Get($@) { my ($hash, @a) = @_; my $name = $a[0]; return "$name: get needs at least one parameter" if(@a < 2); my $cmd= $a[1]; my $ret = ""; if( $cmd eq "html" ) { return readingsGroup_2html($hash); } return undef; return "Unknown argument $cmd, choose one of html:noArg"; } 1; =pod =begin html

readingsGroup

=end html =cut