From 643262127b2f23985a95540979218d6e49cc3af1 Mon Sep 17 00:00:00 2001 From: betateilchen <> Date: Mon, 26 Jan 2015 15:13:11 +0000 Subject: [PATCH] contrib/InfoPanel: added for evaluation git-svn-id: https://svn.fhem.de/fhem/trunk@7734 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/InfoPanel/55_InfoPanel.pm | 922 +++++++++++++++++++++++++ fhem/contrib/InfoPanel/demo.layout | 217 ++++++ 2 files changed, 1139 insertions(+) create mode 100644 fhem/contrib/InfoPanel/55_InfoPanel.pm create mode 100644 fhem/contrib/InfoPanel/demo.layout diff --git a/fhem/contrib/InfoPanel/55_InfoPanel.pm b/fhem/contrib/InfoPanel/55_InfoPanel.pm new file mode 100644 index 000000000..a0f085ae9 --- /dev/null +++ b/fhem/contrib/InfoPanel/55_InfoPanel.pm @@ -0,0 +1,922 @@ +############################################## +# +# 55_InfoPanel.pm written by betateilchen +# +# forked from 02_RSS.pm by Dr. Boris Neubert +# +############################################## +# $Id: $ + +# + +package main; +use strict; +use warnings; + +use MIME::Base64; +use Image::Info qw(image_info dim); + +use feature qw/switch/; +use vars qw(%data); +use HttpUtils; + +my @cmd_halign= qw(thalign ihalign); +my @cmd_valign= qw(tvalign ivalign); +my @valid_valign = qw(auto baseline middle center hanging); +my @valid_halign = qw(start middle end); + +no if $] >= 5.017011, warnings => 'experimental::smartmatch'; + +# we can +# use vars qw(%FW_types); # device types, +# use vars qw($FW_RET); # Returned data (html) +# use vars qw($FW_wname); # Web instance +# use vars qw($FW_subdir); # Sub-path in URL for extensions, e.g. 95_FLOORPLAN +# use vars qw(%FW_pos); # scroll position +# use vars qw($FW_cname); # Current connection name + +#sub InfoPanel_Initialize($); +sub btIP_Define($$); +sub btIP_Set; +sub btIP_Notify; +sub btIP_readLayout($); + +sub btIP_itemArea; +sub btIP_itemCircle; +sub btIP_itemDate; +sub btIP_itemEllipse; +sub btIP_itemImg; +sub _btIP_imgData; +sub _btIP_imgRescale; +sub btIP_itemLine; +sub btIP_itemPlot; +sub btIP_itemRect; +sub btIP_itemSeconds; +sub btIP_itemText; +sub btIP_itemTextBox; +sub btIP_itemTime; +sub btIP_color; +sub btIP_xy; + +sub btIP_ReturnSVG($); +sub btIP_evalLayout($$@); + +sub btIP_addExtension($$$); +sub btIP_CGI; +sub btIP_splitRequest($); + +sub btIP_returnHTML($); +sub btIP_getURL($); +sub btIP_HTMLHead($$); +sub btIP_getScript; +sub btIP_HTMLTail; +sub btIP_Overview; + +###################################### + +sub InfoPanel_Initialize($) { + my ($hash) = @_; + $hash->{DefFn} = "btIP_Define"; + #$hash->{AttrFn} = "btIP_Attr"; + $hash->{AttrList} = "autoreload:1,0 bg bgcolor refresh size tmin"; + $hash->{SetFn} = "btIP_Set"; + $hash->{NotifyFn} = "btIP_Notify"; + + btIP_addExtension("btIP_CGI","btip","InfoPanel"); + + return undef; +} + +sub btIP_Define($$) { + + my ($hash, $def) = @_; + + my @a = split("[ \t]+", $def); + + return "Usage: define InfoPanel hostname filename" if(int(@a) != 4); + my $name= $a[0]; + my $hostname= $a[2]; + my $filename= $a[3]; + + $hash->{NOTIFYDEV} = 'global'; + $hash->{fhem}{hostname}= $hostname; + $hash->{fhem}{filename}= $filename; + $hash->{LAYOUTFILE} = $filename; + + btIP_readLayout($hash); + + $hash->{STATE} = 'defined'; + return undef; +} + +sub btIP_Set { + + my ($hash, @a) = @_; + my $name = $a[0]; + + # usage check + my $usage= "Unknown argument, choose one of reread:noArg"; + if((@a == 2) && ($a[1] eq "reread")) { + btIP_readLayout($hash); + return undef; + } else { + return $usage; + } +} + +sub btIP_Notify { + my ($hash,$dev) = @_; + + return unless AttrVal($hash->{NAME},'autoreload',1); + return if($dev->{NAME} ne "global"); + return if(!grep(m/^FILEWRITE $hash->{LAYOUTFILE}$/, @{$dev->{CHANGED}})); + + Log3(undef, 4, "InfoPanel: $hash->{NAME} reread layout after edit."); + undef = btIP_readLayout($hash); + return undef; +} + +sub btIP_readLayout($) { + + my ($hash)= @_; + my $filename= $hash->{fhem}{filename}; + my $name= $hash->{NAME}; + + my ($err, @layoutfile) = FileRead($filename); + if($err) { + Log 1, "InfoPanel $name: $err"; + $hash->{fhem}{layout}= ("text 0.1 0.1 'Error: $err'"); + } else { + $hash->{fhem}{layout}= join("\n", @layoutfile); + $hash->{fhem}{layout} =~ s/\n\n/\n/g; + } + return; +} + + +################## +# +# Layout evaluation +# + +##### Items + +sub btIP_itemArea { + my ($id,$x1,$y1,$x2,$y2,$target,%params)= @_; + $id = ($id eq '-') ? createUniqueId() : $id; + my $width = $x2 - $x1; + my $height = $y2 - $y1; + my $output = "\n"; + $output .= "\n"; + $output .= "\n"; + return $output; +} + +sub btIP_itemCircle { + my ($id,$x,$y,$r,$filled,%params)= @_; + $id = ($id eq '-') ? createUniqueId() : $id; + my $output = "\n" if $type eq 'close'; + $arg = defined($arg) ? $arg : ""; + $id = ($id eq '-') ? createUniqueId() : $id; + return "" if $type eq 'open'; +} + +sub btIP_itemImg { + my ($id,$x,$y,$scale,$srctype,$arg,%params)= @_; + $id = ($id eq '-') ? createUniqueId() : $id; + return unless(defined($arg)); + return if($arg eq ""); + my ($data,$info,$width,$height,$mimetype,$output); + + if($srctype eq 'file') { + Log3(undef,4,"InfoPanel img name: $arg"); + my $length = -s "$arg"; + Log3(undef,4,"InfoPanel img len : $length"); + open(GRAFIK, "<", $arg) or die("File not found $!"); + binmode(GRAFIK); + my $readBytes = read(GRAFIK, $data, $length); + close(GRAFIK); + } elsif ($srctype eq "url" || $srctype eq "urlq") { + if($srctype eq "url") { + $data= GetFileFromURL($arg,3,undef,1); + } else { + $data= GetFileFromURLQuiet($arg,3,undef,1); + } + } elsif ($srctype eq 'data') { + $data = $arg; + } else { + Log3(undef,2,"InfoPanel: unknown sourcetype for image tag"); + return ""; + } + + ($width,$height,$data) = _btIP_imgData($data,$scale); + $output = "\n"; + return $output; +} + +sub _btIP_imgData { + my ($arg,$scale) = @_; + my $info = image_info(\$arg); + my $width = $info->{width}; + my $height = $info->{height}; + ($width,$height)= _btIP_imgRescale($width,$height,$scale) unless $scale eq '1'; + my $mimetype = $info->{file_media_type}; + my $data = "data:$mimetype;base64,".encode_base64($arg); + return ($width,$height,$data); +} + +sub _btIP_imgRescale { + my ($width,$height,$scale) = @_; + if ($scale =~ s/([whWH])([\d]*)/$2/) { + $scale = (uc($1) eq "W") ? $scale/$width : $scale/$height; + } + $width = int($scale*$width); + $height = int($scale*$height); + return ($width,$height); +} + +sub btIP_itemLine { + my ($id,$x1,$y1,$x2,$y2,$th,%params)= @_; + $id = ($id eq '-') ? createUniqueId() : $id; + my ($r,$g,$b,$a) = btIP_color($params{rgb}); + return "\n"; +} + +sub btIP_itemPlot { + my ($id,$x,$y,$scale,$inline,$arg) = @_; + my (@plotName) = split(";",$arg); + $id = ($id eq '-') ? createUniqueId() : $id; + my (@webs,$width,$height,$output,$mimetype,$svgdata); + + @webs=devspec2array("TYPE=FHEMWEB"); + foreach(@webs) { + if(!InternalVal($_,'TEMPORARY',undef)) { + $FW_wname=InternalVal($_,'NAME',''); + last; + } + } + + ($width,$height) = split(",", AttrVal($plotName[0],"plotsize","800,160")); + ($width,$height) = _btIP_imgRescale($width,$height,$scale) unless $scale eq '1'; + + if($inline eq "1") { +# +# embed base64 data +# + $FW_RET = undef; + $FW_webArgs{dev} = $plotName[0]; + $FW_webArgs{logdev} = InternalVal($plotName[0], "LOGDEVICE", ""); + $FW_webArgs{gplotfile} = InternalVal($plotName[0], "GPLOTFILE", ""); + $FW_webArgs{logfile} = InternalVal($plotName[0], "LOGFILE", "CURRENT"); + $FW_pos{zoom} = ($plotName[1]) ? $plotName[1] : 'day'; + $FW_pos{off} = ($plotName[2]) ? $plotName[2] : undef; + + ($mimetype, $svgdata) = SVG_showLog("unused"); + $svgdata =~ s/<\/svg>/<\/svg>/; +# $svgdata =~ s/\n"; + + } else { +# +# embed link to plot +# + my $url; + $url = "$FW_ME/SVG_showLog?dev=". $plotName[0]. + "&logdev=". InternalVal($plotName[0], "LOGDEVICE", ""). + "&gplotfile=". InternalVal($plotName[0], "GPLOTFILE", ""). + "&logfile=". InternalVal($plotName[0], "LOGFILE", "CURRENT"); + $url .= "&pos=". ($plotName[1]) ? $plotName[1] : 'day'; + $url .= "&zoom=". ($plotName[2]) ? $plotName[2] : undef; + + $output = "\n"; + } + + return $output; +} + +sub btIP_itemRect { + my ($id,$x1,$y1,$x2,$y2,$rx,$ry,$filled,%params)= @_; + $id = ($id eq '-') ? createUniqueId() : $id; + my $width = $x2 - $x1; + my $height = $y2 - $y1; + my $output = "\n$text\n\n"; + + return $output; +} + +sub btIP_itemTextBox { + my ($id,$x,$y,$boxwidth,$text,%params)= @_; + return unless(defined($text)); + $id = ($id eq '-') ? createUniqueId() : $id; + my ($r,$g,$b,$a) = btIP_color($params{rgb}); + + my $output = " ". + "

$text

". + "
\n"; + + return $output; # btIP_itemText($id,$x,$y,'Textbox not supported',%params); +} + +sub btIP_itemTime { + my ($id,$x,$y,%params)= @_; + $id = ($id eq '-') ? createUniqueId() : $id; + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + return btIP_itemText($id,$x,$y,sprintf("%02d:%02d", $hour, $min),%params); +} + +##### Helper + +sub btIP_color { + my ($rgb)= @_; + my $alpha = 1; + my @d= split("", $rgb); + if(length($rgb) == 8) { + $alpha = hex("$d[6]$d[7]"); + $alpha = $alpha/255; + } + return (hex("$d[0]$d[1]"),hex("$d[2]$d[3]"),hex("$d[4]$d[5]"),$alpha); +} + +sub btIP_xy { + my ($x,$y,%params)= @_; + + $x = $params{xx} if($x eq 'x'); + $y = $params{yy} if($y eq 'y'); + if((-1 < $x) && ($x < 1)) { $x *= $params{width}; } + if((-1 < $y) && ($y < 1)) { $y *= $params{height}; } + return($x,$y); +} + + +################## +# +# create SVG content +# + +sub btIP_returnSVG($) { + my ($name)= @_; + + + # + # increase counter + # + if(defined($defs{$name}{fhem}) && defined($defs{$name}{fhem}{counter})) { + $defs{$name}{fhem}{counter}++; + } else { + $defs{$name}{fhem}{counter}= 1; + } + + my ($width,$height)= split(/x/, AttrVal($name,"size","800x600")); + my $bgcolor = AttrVal($name,'bgcolor','000000'); + + our $svg; + + eval { + + $svg = "\n= $tmin) { + $defs{$name}{fhem}{t}= $t1; + $bgnr++; + } + # detect pictures +# if(opendir(BGDIR, $bgdir)){ +# my @bgfiles= grep {$_ !~ /^\./} readdir(BGDIR); +# +# #foreach my $f (@bgfiles) { +# # Debug sprintf("File \"%s\"\n", $f); +# #} +# closedir(BGDIR); +# # get item number +# if($#bgfiles>=0) { +# if($bgnr > $#bgfiles) { $bgnr= 0; } +# $defs{$name}{fhem}{bgnr}= $bgnr; +# my $bgfile= $bgdir . "/" . $bgfiles[$bgnr]; +# my $filetype =(split(/\./,$bgfile))[-1]; +# my $bg; +# $bg= newFromGif GD::Image($bgfile) if $filetype =~ m/^gif$/i; +# $bg= newFromJpeg GD::Image($bgfile) if $filetype =~ m/^jpe?g$/i; +# $bg= newFromPng GD::Image($bgfile) if $filetype =~ m/^png$/i; +# if(defined($bg)) { +# my ($bgwidth,$bgheight)= $bg->getBounds(); +# if($bgwidth != $width or $bgheight != $height) { +# # we need to resize +# my ($w,$h); +# my ($u,$v)= ($bgwidth/$width, $bgheight/$height); +# if($u>$v) { +# $w= $width; +# $h= $bgheight/$u; +# } else { +# $h= $height; +# $w= $bgwidth/$v; +# } +# $svg->copyResized($bg,($width-$w)/2,($height-$h)/2,0,0,$w,$h,$bgwidth,$bgheight); +# } else { +# # size is as required +# # kill the predefined image and take the original +# undef $svg; +# $svg= $bg; +# } +# } else { +# undef $svg; +# $reason= "Something was wrong with background image \"$bgfile\"."; +# } +# } +# } # end opendir() + } # end defined() + + $svg .= "\" >\n\n"; + $svg = btIP_evalLayout($svg, $name, $defs{$name}{fhem}{layout}); + + $defs{$name}{STATE} = localtime(); + + + }; #warn $@ if $@; + if($@) { + my $msg= $@; + chomp $msg; + Log3 $name, 2, $msg; + } + + $svg .= "Sorry, your browser does not support inline SVG.\n\n"; + + return $svg; + +} + +sub btIP_evalLayout($$@) { + my ($svg,$name,$layout)= @_; + my ($width,$height)= split(/x/, AttrVal($name,"size","800x600")); + my @layout= split("\n", $layout); + + my %params; + $params{width}= $width; + $params{height}= $height; + $params{font}= "Arial"; + $params{pt}= 12; + $params{rgb}= "ffffff"; + $params{condition} = 1; + # we need two pairs of align parameters + # due to different default values for text and img + $params{ihalign} = 'left'; + $params{ivalign} = 'top'; + $params{thalign} = 'start'; + $params{tvalign} = 'auto'; + $params{linespace} = 0; + $params{xx}= 0; + $params{yy}= 0; + + + my ($id,$x,$y,$x1,$y1,$x2,$y2,$r1,$r2); + my ($scale,$inline,$boxwidth,$boxheight); + my ($text,$imgtype,$srctype,$arg,$format); + + my $cont= ""; + foreach my $line (@layout) { + # kill trailing newline + chomp $line; + # kill comments and blank lines + $line=~ s/\#.*$//; + $line=~ s/\s+$//; + $line= $cont . $line; + if($line=~ s/\\$//) { $cont= $line; undef $line; } + next unless($line); + $cont= ""; + #Debug "$name: evaluating >$line<"; + # split line into command and definition + my ($cmd, $def)= split("[ \t]+", $line, 2); + +# Debug "CMD= \"$cmd\", DEF= \"$def\""; + + # separate condition handling + if($cmd eq 'condition') { + $params{condition} = AnalyzePerlCommand(undef, $def); + next; + } + next unless($params{condition}); + +# Debug "before command $line: x= " . $params{xx} . ", y= " . $params{yy}; + + eval { + given($cmd) { + + when("area") { + ($id,$x1,$y1,$x2,$y2,$arg)= split("[ \t]+", $def, 6); + ($x1,$y1)= btIP_xy($x1,$y1,%params); + ($x2,$y2)= btIP_xy($x2,$y2,%params); + $params{xx} = $x; + $params{yy} = $y; + $svg .= btIP_itemArea($id,$x1,$y1,$x2,$y2,$arg,%params); + } + + when("circle") { + ($id,$x1,$y1,$r1,$format)= split("[ \t]+", $def, 5); + ($x1,$y1)= btIP_xy($x1,$y1,%params); + $format //= 0; # set format to 0 as default (not filled) + $svg .= btIP_itemCircle($id,$x1,$y1,$r1,$format,%params); + } + + when("date") { + ($id,$x,$y)= split("[ \t]+", $def, 3); + ($x,$y)= btIP_xy($x,$y,%params); + $params{xx} = $x; + $params{yy} = $y; + $svg .= btIP_itemDate($id,$x,$y,%params); + } + + when("ellipse") { + ($id,$x1,$y1,$r1,$r2,$format)= split("[ \t]+", $def, 6); + ($x1,$y1)= btIP_xy($x1,$y1,%params); + $format //= 0; # set format to 0 as default (not filled) + $svg .= btIP_itemEllipse($id,$x1,$y1,$r1,$r2,$format,%params); + } + + when("font") { + $params{font} = $def; + } + + when("font") { + $params{font} = $def; + } + + when("group") { + ($id,$text,$arg) = split("[ \t]+", $def, 3); + my $arg = AnalyzePerlCommand(undef, $arg); + $svg .= btIP_itemGroup($id,$text,$arg); + } + + when("img") { + ($id,$x,$y,$scale,$srctype,$arg)= split("[ \t]+", $def,7); + ($x,$y)= btIP_xy($x,$y,%params); + $params{xx} = $x; + $params{yy} = $y; + my $arg= AnalyzePerlCommand(undef, $arg); + $svg .= btIP_itemImg($id,$x,$y,$scale,$srctype,$arg,%params); + } + + when("line") { + ($id,$x1,$y1,$x2,$y2,$format)= split("[ \t]+", $def, 6); + ($x1,$y1)= btIP_xy($x1,$y1,%params); + ($x2,$y2)= btIP_xy($x2,$y2,%params); + $format //= 1; # set format to 1 as default thickness for the line + $svg .= btIP_itemLine($id,$x1,$y1,$x2,$y2, $format,%params); + } + + when("linespace") { + $params{linespace}= $def; + } + + when("moveby") { + my ($byx,$byy)= split('[ \t]+', $def, 2); + my ($x,$y)= btIP_xy($byx,$byy,%params); + $params{xx} += $x; + $params{yy} += $y; + } + + when("moveto") { + my ($tox,$toy)= split('[ \t]+', $def, 2); + my ($x,$y)= btIP_xy($tox,$toy,%params); + $params{xx} = $x; + $params{yy} = $y; + } + + when("plot") { + ($id,$x,$y,$scale,$inline,$arg)= split("[ \t]+", $def,6); + ($x,$y)= btIP_xy($x,$y,%params); + $params{xx} = $x; + $params{yy} = $y; + my $arg = AnalyzePerlCommand(undef, $arg); + $svg .= btIP_itemPlot($id,$x,$y,$scale,$inline,$arg,%params); + } + + when("pt") { + $def = AnalyzePerlCommand(undef, $def); + if($def =~ m/^[+-]/) { + $params{pt} += $def; + } else { + $params{pt} = $def; + } + $params{pt} = 6 if($params{pt} < 0); + } + + when("rect") { + ($id,$x1,$y1,$x2,$y2,$r1,$r2,$format)= split("[ \t]+", $def, 8); + ($x1,$y1)= btIP_xy($x1,$y1,%params); + ($x2,$y2)= btIP_xy($x2,$y2,%params); + $params{xx} = $x; + $params{yy} = $y; + $format //= 0; # set format to 0 as default (not filled) + $svg .= btIP_itemRect($id,$x1,$y1,$x2,$y2,$r1,$r2,$format,%params); + } + + when("rgb"){ + $def = "\"$def\"" if(length($def) == 6 && $def =~ /[[:xdigit:]]{6}/); + $params{rgb} = AnalyzePerlCommand(undef, $def); + } + + when("seconds") { + ($id,$x,$y,$format) = split("[ \+]", $def,4); + ($x,$y)= btIP_xy($x,$y,%params); + $params{xx} = $x; + $params{yy} = $y; + $svg .= btIP_itemSeconds($id,$x,$y,$format,%params); + } + +# when("svgimg") { +# ($x,$y,$widht,$height,$imgtype,$srctype,$arg)= split("[ \t]+", $def,6); +# ($x,$y)= btIP_xy( $x,$y,%params); +# $params{xx} = $x; +# $params{yy} = $y; +# my $arg= AnalyzePerlCommand(undef, $arg); +# $svg .= btIP_itemSvgImg($id,$x,$y,$scale,$imgtype,$srctype,$arg,%params); +# } + + when("text") { + ($id,$x,$y,$text)= split("[ \t]+", $def, 4); + ($x,$y)= btIP_xy($x,$y,%params); + $params{xx} = $x; + $params{yy} = $y; + my $txt= AnalyzePerlCommand(undef, $text); + $svg .= btIP_itemText($id,$x,$y,$txt,%params); + } + + when("textbox") { + ($id,$x,$y,$boxwidth,$text)= split("[ \t]+", $def, 5); + ($x,$y)= btIP_xy($x,$y,%params); + my $txt= AnalyzePerlCommand(undef, $text); + $svg .= btIP_itemTextBox($id,$x,$y,$boxwidth,$txt,%params); +# $params{xx} = $x; +# $params{yy} = $y; + } + + when("time") { + ($id,$x,$y)= split("[ \t]+", $def, 3); + ($x,$y)= btIP_xy($x,$y,%params); + $params{xx} = $x; + $params{yy} = $y; + $svg .= btIP_itemTime($id,$x,$y,%params); + } + + default { + if($cmd ~~ @cmd_halign) { + my $d = AnalyzePerlCommand(undef, $def); + if($d ~~ @valid_halign) { + $params{ihalign}= $d unless($cmd eq "thalign"); + $params{thalign}= $d unless($cmd eq "ihalign"); + } else { + Log3 $name, 2, "InfoPanel: $name Illegal horizontal alignment $d"; + } + } elsif($cmd ~~ @cmd_valign) { + my $d = AnalyzePerlCommand(undef, $def); + if( $d ~~ @valid_valign) { + $params{ivalign}= $d unless($cmd eq "tvalign"); + $params{tvalign}= $d unless($cmd eq "ivalign"); + } else { + Log3 $name, 2, "InfoPanel: $name: Illegal vertical alignment $d"; + } + } else { + Log3 $name, 2, "InfoPanel $name: Illegal command $cmd in layout definition."; + } + } # default + } # given + } # eval + +# Debug "after command $line: x= " . $params{xx} . ", y= " . $params{yy}; + + } # foreach + return $svg; +} + +################## +# +# here we answer any request to http://host:port/fhem/rss and below +# + +sub btIP_addExtension($$$) { + my ($func,$link,$friendlyname)= @_; + + my $url = "/" . $link; + $data{FWEXT}{$url}{FUNC} = $func; + $data{FWEXT}{$url}{LINK} = $link; + $data{FWEXT}{$url}{NAME} = $friendlyname; + $data{FWEXT}{$url}{FORKABLE} = 0; +} + +sub btIP_CGI{ + + my ($request) = @_; + + my ($name,$ext)= btIP_splitRequest($request); + + if(defined($name)) { + if($ext eq "") { + return("text/plain; charset=utf-8", "Illegal extension."); + } + if(!defined($defs{$name})) { + return("text/plain; charset=utf-8", "Unknown InfoPanel device: $name"); + } + if($ext eq "info") { + return btIP_returnHTML($name); + } + } else { + return btIP_Overview(); + } + +} + +sub btIP_splitRequest($) { + + my ($request) = @_; + + if($request =~ /^.*\/btip$/) { + # http://localhost:8083/fhem/btip + return (undef,undef); # name, ext + } else { + my $call= $request; + $call =~ s/^.*\/btip\/([^\/]*)$/$1/; + my $name= $call; + $name =~ s/^(.*)\.(svg|info|html)$/$1/; + my $ext= $call; + $ext =~ s/^$name\.(.*)$/$1/; + return ($name,$ext); + } +} + + +#################### +# +# HTML Stuff +# + +sub btIP_returnHTML($) { + my ($name) = @_; + + my $url= btIP_getURL($defs{$name}{fhem}{hostname}); + my $refresh= AttrVal($name, 'refresh', 60); + my $areas= AttrVal($name, 'areas', ""); + + my $code = btIP_HTMLHead($name,$refresh); + + $code .= "\n". +# "\n". +# "\n$areas\n\n". + btIP_returnSVG($name). + "\n". btIP_HTMLTail(); + + return ("text/html; charset=utf-8", $code); +} + +sub btIP_getURL($) { + my ($hostname)= @_; + # http://hostname:8083/fhem + my $proto = (AttrVal($FW_wname, 'HTTPS', 0) == 1) ? 'https' : 'http'; + return $proto."://$hostname:" . $defs{$FW_wname}{PORT} . $FW_ME; +} + +sub btIP_HTMLHead($$) { + my ($title,$refresh) = @_; + +# my $doctype= ''; +# my $xmlns= 'xmlns="http://www.w3.org/1999/xhtml"'; + my $doctype= ' '."\n". + ''."\n"; + my $xmlns= ""; + + my $r= (defined($refresh) && $refresh) ? "\n" : ""; + # css and js header output should be coded only in one place + my $css= ""; + my $scripts= btIP_getScript(); + my $code= "$doctype\n\n\n$title\n$r$css$scripts\n"; + return $code; +} + +sub btIP_getScript { + + my $scripts= ""; + my $jsTemplate = ''; + if(defined($data{FWEXT})) { + foreach my $k (sort keys %{$data{FWEXT}}) { + my $h = $data{FWEXT}{$k}; + next if($h !~ m/HASH/ || !$h->{SCRIPT}); + my $script = $h->{SCRIPT}; + $script = ($script =~ m,^/,) ? "$FW_ME$script" : "$FW_ME/pgm2/$script"; + $scripts .= sprintf($jsTemplate, $script) . "\n"; + } + } + return $scripts; +} + +sub btIP_HTMLTail { + return ""; +} + +sub btIP_Overview { + my ($name, $url); + my $html= btIP_HTMLHead("InfoPanel Overview", undef) . "\n"; + foreach my $def (sort keys %defs) { + if($defs{$def}{TYPE} eq "InfoPanel") { + $name= $defs{$def}{NAME}; + $url= btIP_getURL($defs{$def}{fhem}{hostname}); + $html.= "$name
\n\n

\n"; + } + } + $html.="\n" . btIP_HTMLTail(); + + return ("text/html; charset=utf-8", $html); +} + + +1; + +# diff --git a/fhem/contrib/InfoPanel/demo.layout b/fhem/contrib/InfoPanel/demo.layout new file mode 100644 index 000000000..5a8ccf7a7 --- /dev/null +++ b/fhem/contrib/InfoPanel/demo.layout @@ -0,0 +1,217 @@ +############################################################ +# +# Demo Layoutfile +# +# to use in fhem, copy this file into moddir ./FHEM/ +# and define an InfoPanel device: +# +# define demo InfoPanel ./FHEM/demo.layout +# +############################################################ + + +# +# Schriftartfamilie festlegen +# + +font arial + + +# Farbe für die nächsten Aktionen festlegen +# gültig bis zur nächsten Definition per rgb +# +# Format: rrggbbaa +# rr gg bb = rgb Werte (hexadezimal) +# aa = Deckkraft (hexadezimal) je höher der Wert, +# umso höher die Deckkraft +# + +rgb "7F7F7FFF" # graue, voll deckend + + +# Linien zeichnen +# +# Format: line [] +# id = Name des Objekts +# x1,y1 = obere linke Ecke des Rechtecks +# x2 y2 = untere rechte Ecke des Rechtecks +# th = Linienstärke (in Pixel), optional, default=1 +# +line - 0 150 800 150 2 +line - 200 0 200 400 2 + +line - 0 400 800 400 +line - 600 0 600 400 + +rgb "00FF00FF" # Fadenkreuz in grün +line - 400 100 400 400 +line - 100 300 700 300 + + +# pt Schriftgröße in Pixel +# gültig bis zur nächsten Definition +# +pt 24 + +rgb "FFFFFFFF" # Schriftfarbe weiß, voll deckend + + +# Text zentriert ausgeben +# +thalign "middle" + +# Text ausgeben +# Format: text {} +# +text - 400 25 "InfoPanel" + + +# Text linksbündig ausgeben +# +thalign "start" + + +# Datum ausgeben +# Format: date +# +date - 50 25 + + +# Text rechtsbündig ausgeben +# +thalign "end" + + +# Uhrzeit ausgeben +# Format: time +# +time - 750 25 + + +# Rechteck zeichnen +# Format: rect [] +# id = Name des Objekts +# x1,y1 = obere linke Ecke des Rechtecks +# x2 y2 = untere rechte Ecke des Rechtecks +# rx,ry = Radien für abgerundete Ecken +# filled = Rechteck füllen (0|1) +# + +rgb FF00007F + +rect - 200 150 400 300 0 0 1 # rot gefüllt ohne Abrundung +rect - 410 160 590 290 10 10 1 # rot gefüllt mit runden Ecken + + +# Rechteck als Link festlegen +# Format: area +# id = Name des Objekts +# x1,y1 = obere linke Ecke des Rechtecks +# x2 y2 = untere rechte Ecke des Rechtecks +# target = Ziel-URL +# + +# wir verwenden das linke rote Rechteck +# um zu fhem zu verlinken + +area - 200 150 400 300 http://www.fhem.de + + +# condition funktioniert wie in 02_RSS.pm +# +# condition { ReadingsVal('HMinfo', 'ERR_battery', 0) } +condition 1 + + +# Grafiken einbinden +# Format: img +# id = Name des Objekts +# x,y = obere linke Ecke der Grafik +# + +# wir legen ein rotes Quadrat 48x48 hinter das Bild +rgb "FF0000FF" +rect - 700 200 747 247 2 2 1 + +# jetzt kommt das Bild in einer Skalierung +# Breite = 46 Pixel +# +img - 701 201 w46 file "./www/images/fhemSVG/batterie.svg" + + +# Kreis zeichnen +# Format: circle [] +# id = Name des Objekts +# x,y = Mittelpunkt des Kreises +# r = Radius +# filled = Rechteck füllen (0|1) +# + +rgb "FFFF005F" # gelb + +circle - 700 350 50 1 +circle - 720 370 10 0 + + +# Kreis zeichnen +# Format: ellipse [] +# id = Name des Objekts +# x,y = Mittelpunkt des Kreises +# rx,ry = Radien der Ellipse +# r = Radius +# filled = Rechteck füllen (0|1) +# + +rgb "0000FF5F" # blau + +ellipse - 100 300 50 70 1 +ellipse - 100 300 30 20 0 + + +# Plots aus fhem einbinden +# Format: +# id = Name des Objekts +# x,y = obere linke Ecke des Plots +# scale = Skalierungsfaktor +# inline = Plot als Link (0) oder als BASE64 (1) einfügen +# Plotname = Name des SVG devices in fhem +# zoom = Darstellungsbereich des Plots +# offset = Offset des Plots +# + +# bei Bedarf ein farbiges Rechteck hinter den Plot legen: +# +rgb "5858587F" # dunkelgrau +rect - 0 420 800 580 5 5 1 + +# jetzt den Plot einbinden +plot - 0 420 1 1 "SVG_out_Balkon;day" + + +rgb "FFFFFFFF" +thalign "start" + +# Textausrichtung vertikal +# +tvalign "baseline" +text - 10 150 "baseline" + +tvalign "middle" +text - 110 150 "middle" + +tvalign "center" +text - 610 150 "center" + +tvalign "hanging" +text - 710 150 "hanging" + +tvalign "baseline" + + +# Sekunden anzeigen: +# Format: seconds [colon] +# +seconds - 300 350 # Sekunden ohne Doppelpunkt anzeigen +seconds - 500 350 colon # Sekunden mit Doppelpunkt anzeigen + +# \ No newline at end of file