WebPgm2 gnuplot scrolling

git-svn-id: https://svn.fhem.de/fhem/trunk@198 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig
2008-06-12 07:22:59 +00:00
parent ca30c239d2
commit b8d9314e2a
18 changed files with 608 additions and 55 deletions

View File

@@ -405,3 +405,5 @@
them them
- feature: M232 add windows support (thomas 12.05.08) - feature: M232 add windows support (thomas 12.05.08)
- feature: add simple ELV IPWE1 support (thomas 12.05.08) - feature: add simple ELV IPWE1 support (thomas 12.05.08)
- feature: FileLog get to read logfiles. Used heavily by webpgm2
- feature: webpgm2: gnuplot-scroll mode to navigate/zoom in logfiles

View File

@@ -5,6 +5,8 @@ use strict;
use warnings; use warnings;
use IO::File; use IO::File;
sub seekTo($$$$);
##################################### #####################################
sub sub
FileLog_Initialize($) FileLog_Initialize($)
@@ -141,35 +143,167 @@ FileLog_Set($@)
} }
################################### ###################################
# We use this function to be able to scroll/zoom in the plots created from the
# logfile. When outfile is specified, it is used with gnuplot post-processing,
# when outfile is "-" it is used to create SVG graphics
#
# Up till now following functions are impemented:
# - int (to cut off % from a number, as for the actuator)
# - delta-h / delta-d to get rain/h and rain/d values from continuous data.
sub sub
FileLog_Get($@) FileLog_Get($@)
{ {
my ($hash, @a) = @_; my ($hash, @a) = @_;
return "Usage: get $a[0] <from> <to> <column_list>" if(int(@a) != 4); return "Usage: get $a[0] <infile> <outfile> <from> <to> <column_spec> ...\n" .
my $fh = new IO::File $hash->{currentlogfile}; " where column_spec is <col>:<regexp>:<fn>\n" .
seekTo($fh, $hash, $a[1]); " see the FileLogGrep entries in he .gplot files\n" .
# my @arr = " <infile> is without direcory, - means the current file\n" .
my $data=''; " <outfile> is a prefix, - means stdout\n"
while(my $l = <$fh>) { if(int(@a) < 5);
last if($l gt $a[2]);
$data.=$l;
}
close($fh);
return "EOF" if(!defined($data));
return $data; shift @a;
my $inf = shift @a;
my $outf = shift @a;
my $from = shift @a;
my $to = shift @a;
if($inf eq "-") {
$inf = $hash->{currentlogfile};
} else {
my $linf = "$1/$inf" if($hash->{currentlogfile} =~ m,^(.*)/[^/]*$,);
if(!-f $linf) {
$linf = $attr{$hash->{NAME}}{archivedir} . "/" . $inf;
return "Error: File-not-found" if(!-f $linf);
}
$inf = $linf;
}
my $ifh = new IO::File $inf;
seekTo($inf, $ifh, $hash, $from);
#############
# Digest the input.
# last1: first delta value after d/h change
# last2: last delta value recorded (for the very last entry)
# last3: last delta timestamp (d or h)
my (@d, @fname);
for(my $i = 0; $i < int(@a); $i++) {
my @fld = split(":", $a[$i], 3);
my %h;
if($outf ne "-") {
$fname[$i] = "$outf.$i";
$h{fh} = new IO::File "> $fname[$i]";
}
$h{re} = $fld[1];
$h{fn} = $fld[2];
$h{didx} = 2 if($fld[2] && $fld[2] eq "delta-d");
$h{didx} = 3 if($fld[2] && $fld[2] eq "delta-h");
if($fld[0] =~ m/"(.*)"/) {
$h{col} = $1;
$h{isfix} = 1;
} else {
$h{col} = $fld[0]-1;
}
$h{ret} = [];
$d[$i] = \%h;
}
my %lastdate;
while(my $l = <$ifh>) {
last if($l gt $to);
my @fld = split("[ \r\n]+", $l);
for(my $i = 0; $i < int(@a); $i++) { # Process each req. field
my $h = $d[$i];
my $re = $h->{re};
next if($re && $l !~ m/$re/);
my $col = $h->{col};
my $line = "";
if($h->{isfix}) { # Fixed text
$line = "$fld[0] $col";
} elsif(!$h->{fn}) { # The column
$line = "$fld[0] $fld[$col]";
} elsif($h->{fn} eq "int") { # int function
my $val = $fld[$col];
$val =~ s/[^\d.]//;
$line = "$fld[0] $val";
} elsif($h->{didx}) { # delta-h or delta-d
my $hd = $h->{didx};
my @ld = split("[-_:]", $fld[0]);
if(!defined($h->{last1}) || $h->{last3} ne $ld[$hd]) {
if(defined($h->{last1})) {
my @lda = split("[_:]", $lastdate{$hd});
my $ts = "12:00:00"; # middle timestamp
$ts = "$lda[1]:30:00" if($hd == 3);
$line = sprintf("%s_%s %0.1f", $lda[0],$ts, $fld[$col]-$h->{last1});
}
$h->{last1} = $fld[$col];
$h->{last3} = $ld[$hd];
}
$h->{last2} = $fld[$col];
$lastdate{$hd} = $fld[0];
} else {
$line = "$fld[0] " . eval($h->{fn});
}
next if(!$line);
if($outf eq "-") {
push @{$h->{ret}}, $line;
} else {
my $fh = $h->{fh};
print $fh $line,"\n";
}
}
}
$ifh->close();
my $ret = "";
for(my $i = 0; $i < int(@a); $i++) {
my $h = $d[$i];
my $hd = $h->{didx};
if($hd && $lastdate{$hd}) {
my $val = defined($h->{last1}) ? $h->{last2}-$h->{last1} : 0;
my @lda = split("[_:]", $lastdate{$hd});
my $ts = "12:00:00"; # middle timestamp
$ts = "$lda[1]:30:00" if($hd == 3);
my $line = sprintf("%s_%s %0.1f", $lda[0],$ts, $h->{last2}-$h->{last1});
if($outf eq "-") {
push @{$h->{ret}}, $line;
} else {
my $fh = $h->{fh};
print $fh $line,"\n";
}
}
if($outf eq "-") {
$ret .= join("\n", @{$h->{ret}}) if($h->{ret});
} else {
$h->{fh}->close();
}
}
return ($outf eq "-") ? $ret : join(" ", @fname);
} }
################################### ###################################
sub sub
seekTo($$$) seekTo($$$$)
{ {
my ($fh, $hash, $ts) = @_; my ($fname, $fh, $hash, $ts) = @_;
# If its cached # If its cached
if($hash->{pos} && $hash->{pos}{$ts}) { if($hash->{pos} && $hash->{pos}{"$fname:$ts"}) {
$fh->seek($hash->{pos}{$ts}, 0); $fh->seek($hash->{pos}{"$fname:$ts"}, 0);
return; return;
} }
@@ -183,17 +317,21 @@ seekTo($$$)
if($data !~ m/^20\d\d-\d\d-\d\d_\d\d:\d\d:\d\d /) { if($data !~ m/^20\d\d-\d\d-\d\d_\d\d:\d\d:\d\d /) {
$next = $fh->tell; $next = $fh->tell;
$data = <$fh>; $data = <$fh>;
$next = $last if(!$data);
}
if($next eq $last) {
$fh->seek($next, 0);
last;
} }
last if($next eq $last);
$last = $next; $last = $next;
if($data lt $ts) { if(!$data || $data lt $ts) {
($lower, $next) = ($next, ($next+$upper)/2); ($lower, $next) = ($next, ($next+$upper)/2);
} else { } else {
($upper, $next) = ($next, ($lower+$next)/2); ($upper, $next) = ($next, ($lower+$next)/2);
} }
} }
$hash->{pos}{$ts} = $last; $hash->{pos}{"$fname:$ts"} = $last;
} }

View File

@@ -284,3 +284,13 @@
- Peter S. Mon Jun 02 00:39 MET 2008 - Peter S. Mon Jun 02 00:39 MET 2008
- linux.html: openSUSE 11 contains our changes. - linux.html: openSUSE 11 contains our changes.
- Thu Jun 12 07:15:03 MEST 2008
- feature: FileLog get to read logfiles / webpgm2: gnuplot-scroll mode to
navigate/zoom in logfiles
webpgm2 uses the FileLog get to grep data for a given data range from a
logfile. Using this grep scrolling to a different date range / zooming
to another resolution (day/week/month/year) can be implemented.
The logfiles should be large, as scrolling across logfiles is not
implemented. To speed up the grep, a binary search with seek is used, and
seek positions are cached.

View File

@@ -35,11 +35,13 @@ sub FHEMWEB_showLogWrapper($);
sub FHEMWEB_popup($$$); sub FHEMWEB_popup($$$);
sub FHEMWEB_textfield($$); sub FHEMWEB_textfield($$);
sub FHEMWEB_submit($$); sub FHEMWEB_submit($$);
sub __roomOverview(); sub FHEMWEB_roomOverview();
sub FHEMWEB_fatal($); sub FHEMWEB_fatal($);
sub pF($@); sub pF($@);
sub pO(@); sub pO(@);
sub FHEMWEB_AnswerCall($); sub FHEMWEB_AnswerCall($);
sub FHEMWEB_zoomLink($$$$);
sub FHEMWEB_calcWeblink($$);
######################### #########################
# As we are _not_ multithreaded, it is safe to use global variables. # As we are _not_ multithreaded, it is safe to use global variables.
@@ -52,10 +54,15 @@ my $__room;
my $__detail; my $__detail;
my $__title; my $__title;
my $__cmdret; my $__cmdret;
my $__scrolledweblinkcount;
my %__wlpos;
my $__RET; my $__RET;
my $__RETTYPE; my $__RETTYPE;
my $__SF; my $__SF;
my $__ti; # Tabindex for all input fields my $__ti; # Tabindex for all input fields
my @__zoom;
my %__zoom;
my $__plotmode;
##################################### #####################################
@@ -68,7 +75,7 @@ FHEMWEB_Initialize($)
$hash->{DefFn} = "FHEMWEB_Define"; $hash->{DefFn} = "FHEMWEB_Define";
$hash->{UndefFn} = "FHEMWEB_Undef"; $hash->{UndefFn} = "FHEMWEB_Undef";
$hash->{AttrList}= "loglevel:0,1,2,3,4,5,6 fhemwebdir fhemwebname"; $hash->{AttrList}= "loglevel:0,1,2,3,4,5,6 webdir webname plotmode:gnuplot,gnuplot-scroll,SVG";
} }
##################################### #####################################
@@ -95,6 +102,12 @@ FHEMWEB_Define($$)
$hash->{SERVERSOCKET} = "True"; $hash->{SERVERSOCKET} = "True";
Log(2, "FHEMWEB port $port opened"); Log(2, "FHEMWEB port $port opened");
###############
# Initialize internal structures
my $n = 0;
@__zoom = ("day","week","month","year");
%__zoom = map { $_, $n++ } @__zoom;
return undef; return undef;
} }
@@ -145,10 +158,10 @@ FHEMWEB_Read($)
my $name = $hash->{SNAME}; my $name = $hash->{SNAME};
my $ll = GetLogLevel($name,4); my $ll = GetLogLevel($name,4);
$FHEMWEBdir = ($attr{$name} && $attr{$name}{fhemwebdir}) ? $FHEMWEBdir = ($attr{$name} && $attr{$name}{webdir}) ?
$attr{$name}{fhemwebdir} : "$attr{global}{modpath}/FHEM"; $attr{$name}{webdir} : "$attr{global}{modpath}/FHEM";
$__ME = "/" . (($attr{$name} && $attr{$name}{fhemwebname}) ? $__ME = "/" . (($attr{$name} && $attr{$name}{webname}) ?
$attr{$name}{fhemwebname} : "fhem"); $attr{$name}{webname} : "fhem");
$FHEMWEB_reldoc = "$__ME/commandref.html"; $FHEMWEB_reldoc = "$__ME/commandref.html";
$__SF = "<form method=\"get\" action=\"$__ME\">"; $__SF = "<form method=\"get\" action=\"$__ME\">";
@@ -173,16 +186,16 @@ FHEMWEB_Read($)
$hash->{BUF} = ""; $hash->{BUF} = "";
Log($ll, "HTTP $hash->{NAME} GET $arg"); Log($ll, "HTTP $hash->{NAME} GET $arg");
$__plotmode = $attr{$name}{plotmode} ? $attr{$name}{plotmode} : "gnuplot";
FHEMWEB_AnswerCall($arg); FHEMWEB_AnswerCall($arg);
my $c = $hash->{CD}; my $c = $hash->{CD};
my $l = length($__RET); my $l = length($__RET);
my $exp = localtime(time()+300) . " GMT"; # my $exp = localtime(time()+300) . " GMT";
# "Expires: $exp\r\n",
print $c "HTTP/1.1 200 OK\r\n", print $c "HTTP/1.1 200 OK\r\n",
"Content-Length: $l\r\n", "Content-Length: $l\r\n",
"Expires: $exp\r\n",
"Content-Type: $__RETTYPE\r\n\r\n", "Content-Type: $__RETTYPE\r\n\r\n",
$__RET; $__RET;
} }
@@ -195,6 +208,7 @@ FHEMWEB_AnswerCall($)
%__rooms = (); %__rooms = ();
%__devs = (); %__devs = ();
%__wlpos = ();
%__types = (); %__types = ();
$__room = ""; $__room = "";
$__detail = ""; $__detail = "";
@@ -266,8 +280,8 @@ FHEMWEB_AnswerCall($)
pO "</div>\n"; pO "</div>\n";
} }
__roomOverview(); FHEMWEB_roomOverview();
FHEMWEB_doDetail($__detail) if($__detail); FHEMWEB_doDetail($__detail) if($__detail);
FHEMWEB_showRoom() if($__room && !$__detail); FHEMWEB_showRoom() if($__room && !$__detail);
FHEMWEB_showLogWrapper($cmd) if($cmd =~ /^showlogwrapper/); FHEMWEB_showLogWrapper($cmd) if($cmd =~ /^showlogwrapper/);
FHEMWEB_showArchive($cmd) if($cmd =~ m/^showarchive/); FHEMWEB_showArchive($cmd) if($cmd =~ m/^showarchive/);
@@ -289,7 +303,7 @@ FHEMWEB_digestCgi($)
$pv =~ s/\+/ /g; $pv =~ s/\+/ /g;
$pv =~ s/%(..)/chr(hex($1))/ge; $pv =~ s/%(..)/chr(hex($1))/ge;
my ($p,$v) = split("=",$pv, 2); my ($p,$v) = split("=",$pv, 2);
$v =~ s/[\r]\n/\\\n/g; $v =~ s/[\r]\n/\\\n/g; # Multiline: escape the NL for fhem
#Log(0, "P: $p, V: $v"); #Log(0, "P: $p, V: $v");
if($p eq "detail") { $__detail = $v; } if($p eq "detail") { $__detail = $v; }
@@ -299,6 +313,9 @@ FHEMWEB_digestCgi($)
if($p =~ m/^val\.(.*)$/) { $val{$1} = $v; } if($p =~ m/^val\.(.*)$/) { $val{$1} = $v; }
if($p =~ m/^dev\.(.*)$/) { $dev{$1} = $v; } if($p =~ m/^dev\.(.*)$/) { $dev{$1} = $v; }
if($p =~ m/^cmd\.(.*)$/) { $cmd = $v; $c= $1; } if($p =~ m/^cmd\.(.*)$/) { $cmd = $v; $c= $1; }
if($p eq "wlpos") { %__wlpos = split(/[=;]/, $v); }
} }
$cmd.=" $dev{$c}" if($dev{$c}); $cmd.=" $dev{$c}" if($dev{$c});
$cmd.=" $arg{$c}" if($arg{$c}); $cmd.=" $arg{$c}" if($arg{$c});
@@ -514,14 +531,30 @@ FHEMWEB_doDetail($)
############## ##############
# Room overview # Room overview
sub sub
__roomOverview() FHEMWEB_roomOverview()
{ {
pO $__SF; pO $__SF;
pO "<div id=\"hdr\">\n"; pO "<div id=\"hdr\">\n";
pO "<table><tr><td>";
pO "<a href=\"$FHEMWEB_reldoc\">Cmd</a>: "; pO "<a href=\"$FHEMWEB_reldoc\">Cmd</a>: ";
pO FHEMWEB_textfield("cmd", 30); pO FHEMWEB_textfield("cmd", 30);
pO FHEMWEB_hidden("room", "$__room") if($__room); $__scrolledweblinkcount = 0;
if($__room) {
pO FHEMWEB_hidden("room", "$__room");
if(!$__detail) { # Global navigation buttons for weblink >= 2
FHEMWEB_calcWeblink(undef,undef);
if($__scrolledweblinkcount) {
pO "</td><td>";
pO "&nbsp;&nbsp;";
FHEMWEB_zoomLink("zoom=-1", "Zoom-in.png", "zoom in", 0);
FHEMWEB_zoomLink("zoom=1", "Zoom-out.png","zoom out", 0);
FHEMWEB_zoomLink("all=-1", "Prev.png", "prev", 0);
FHEMWEB_zoomLink("all=1", "Next.png", "next", 0);
}
}
}
pO "</td></tr></table>";
pO "</div>\n"; pO "</div>\n";
pO "<div id=\"left\">\n"; pO "<div id=\"left\">\n";
@@ -717,8 +750,20 @@ FHEMWEB_showRoom()
$__devs{$va[0]}{INT}{currentlogfile}{VAL} =~ m,([^/]*)$,; $__devs{$va[0]}{INT}{currentlogfile}{VAL} =~ m,([^/]*)$,;
$va[2] = $1; $va[2] = $1;
} }
pO "<td><img src=\"$__ME?cmd=showlog $va[0] $va[1] $va[2]\"/>"; pO "<table><tr><td>";
my $wl = "";
$__wlpos{$va[0]} = $__wlpos{$d} if($__wlpos{$d});
$wl = "&wlpos=" . join(";", map { "$_=$__wlpos{$_}" }
grep { /(zoom|all|$va[0])/ } keys %__wlpos);
pO "<img src=\"$__ME?cmd=showlog $d $va[0] $va[1] $va[2]$wl\"/>";
pO "</td><td>";
FHEMWEB_zoomLink("$d=-1", "Prev.png", "prev", 1);
FHEMWEB_zoomLink("$d=1", "Next.png", "next", 1);
pO "<a href=\"$__ME?detail=$d\">$d</a></td>"; pO "<a href=\"$__ME?detail=$d\">$d</a></td>";
pO "</td></tr></table>";
} }
} }
@@ -756,6 +801,8 @@ FHEMWEB_fileList($)
} }
###################### ######################
# Show the content of the log (plain text), or an image and offer a link
# to convert it to a weblink
sub sub
FHEMWEB_showLogWrapper($) FHEMWEB_showLogWrapper($)
{ {
@@ -782,7 +829,7 @@ FHEMWEB_showLogWrapper($)
pO "<div id=\"right\">\n"; pO "<div id=\"right\">\n";
pO "<table><tr></td>\n"; pO "<table><tr></td>\n";
pO "<table><tr></td>\n"; pO "<table><tr></td>\n";
pO "<td><img src=\"$__ME?cmd=showlog $d $type $file\"/>"; pO "<td><img src=\"$__ME?cmd=showlog undef $d $type $file\"/>";
pO "<a href=\"$__ME?cmd=toweblink $d:$type:$file\"><br>Convert to weblink</a></td>"; pO "<a href=\"$__ME?cmd=toweblink $d:$type:$file\"><br>Convert to weblink</a></td>";
pO "</td></tr></table>\n"; pO "</td></tr></table>\n";
pO "</td></tr></table>\n"; pO "</td></tr></table>\n";
@@ -795,28 +842,83 @@ sub
FHEMWEB_showLog($) FHEMWEB_showLog($)
{ {
my ($cmd) = @_; my ($cmd) = @_;
my (undef, $d, $type, $file) = split(" ", $cmd, 4); my (undef, $wl, $d, $type, $file) = split(" ", $cmd, 5);
$__devs{$d}{INT}{logfile}{VAL} =~ m,^(.*)/([^/]*)$,; # Dir and File
my $path = "$1/$file";
$path = $__devs{$d}{ATTR}{archivedir}{VAL} . "/$file" if(!-f $path);
my $gplot_pgm = "$FHEMWEBdir/$type.gplot"; my $gplot_pgm = "$FHEMWEBdir/$type.gplot";
return FHEMWEB_fatal("Cannot read $gplot_pgm") if(!-r $gplot_pgm); return FHEMWEB_fatal("Cannot read $gplot_pgm") if(!-r $gplot_pgm);
return FHEMWEB_fatal("Cannot read $path") if(!-r $path);
# Read in the template gnuplot file FHEMWEB_calcWeblink($d,$wl);
open(FH, $gplot_pgm) || FHEMWEB_fatal("$gplot_pgm: $!"); if($__plotmode eq "gnuplot" || !$__devs{$d}{from}) {
my $gplot_script = join("", <FH>);
close(FH); # Looking for the logfile....
$gplot_script =~ s/<OUT>/$FHEMWEB_tmpfile/g;
$gplot_script =~ s/<IN>/$path/g; $__devs{$d}{INT}{logfile}{VAL} =~ m,^(.*)/([^/]*)$,; # Dir and File
$gplot_script =~ s/<TL>/$file/g; my $path = "$1/$file";
$path = $__devs{$d}{ATTR}{archivedir}{VAL} . "/$file" if(!-f $path);
return FHEMWEB_fatal("Cannot read $path") if(!-r $path);
open(FH, $gplot_pgm) || FHEMWEB_fatal("$gplot_pgm: $!");
my $gplot_script = join("", <FH>);
close(FH);
$gplot_script =~ s/<OUT>/$FHEMWEB_tmpfile/g;
$gplot_script =~ s/<IN>/$path/g;
$gplot_script =~ s/<TL>/$file/g;
if($__devs{$wl} && $__devs{$wl}{ATTR}{fixedrange}) {
my $fr = $__devs{$wl}{ATTR}{fixedrange}{VAL};
$fr =~ s/ /\":\"/;
$fr = "set xrange [\"$fr\"]\n";
$gplot_script =~ s/(set timefmt ".*")/$1\n$fr/;
}
open(FH, "|gnuplot > /dev/null");# feed it to gnuplot
print FH $gplot_script;
close(FH);
} else { # gnuplot-scroll
############################
# Read in the template gnuplot file. Digest the #FileLog lines. Replace
# the plot directive with our own, as we offer a file for each line
my (@filelog, @data, $plot);
open(FH, $gplot_pgm) || FHEMWEB_fatal("$gplot_pgm: $!");
while(my $l = <FH>) {
if($l =~ m/^#FileLog (.*)$/) {
push(@filelog, $1);
} elsif($l =~ "^plot" || $plot) {
$plot .= $l;
} else {
push(@data, $l);
}
}
close(FH);
my $gplot_script = join("", @data);
$gplot_script =~ s/<OUT>/$FHEMWEB_tmpfile/g;
$gplot_script =~ s/<TL>/$file/g;
my ($f,$t)=($__devs{$d}{from}, $__devs{$d}{to});
my @path = split(" ", fC("get $d $file $FHEMWEB_tmpfile $f $t " .
join(" ", @filelog)));
my $i = 0;
$plot =~ s/\".*?using 1:[^ ]+ /"\"$path[$i++]\" using 1:2 "/gse;
my $xrange = "set xrange [\"$f\":\"$t\"]\n";
foreach my $p (@path) {
next if(!-z $p);
open(FH, ">$p");
print FH "$f 0\n";
close(FH);
}
open(FH, "|gnuplot > /dev/null");# feed it to gnuplot
print FH $gplot_script, $xrange, $plot;
close(FH);
foreach my $p (@path) {
unlink($p);
}
}
open(FH, "|gnuplot > /dev/null");# feed it to gnuplot
print FH $gplot_script;
close(FH);
$__RETTYPE = "image/png"; $__RETTYPE = "image/png";
open(FH, "$FHEMWEB_tmpfile.png"); # read in the result and send it open(FH, "$FHEMWEB_tmpfile.png"); # read in the result and send it
@@ -904,6 +1006,131 @@ FHEMWEB_submit($$)
return $s; return $s;
} }
##################
sub
FHEMWEB_zoomLink($$$$)
{
my ($cmd, $img, $alt, $br) = @_;
my ($d,$off) = split("=", $cmd, 2);
return if($__plotmode eq "gnuplot");
return if($__devs{$d} && $__devs{$d}{ATTR}{fixedrange});
return if($__devs{$d} && $__devs{$d}{ATTR}{noscroll});
my $val = $__wlpos{$d};
$cmd = "room=$__room&wlpos=";
if($d eq "zoom") {
$val = "day" if(!$val);
$val = $__zoom{$val};
return if(!defined($val) || $val+$off < 0 || $val+$off >= int(@__zoom) );
$val = $__zoom[$val+$off];
return if(!$val);
$cmd .= "zoom=$val";
} else {
return if((!$val && $off > 0) || ($val && $val+$off > 0)); # no future
$__wlpos{$d}=($val ? $val+$off : $off);
$cmd .= join(";", map { "$_=$__wlpos{$_}" } sort keys %__wlpos);
if(!defined($val)) {
delete $__wlpos{$d};
} else {
$__wlpos{$d} = $val;
}
}
pO "<a href=\"$__ME?$cmd\">";
pO "<img style=\"border-color:transparent\" alt=\"$alt\" ".
"src=\"$__ME/icons/$img\"/></a>";
pO "<br>" if($br);
}
##################
# Calculate either the number of scrollable weblinks (for $d = undef) or
# for the device the valid from and to dates for the given zoom and offset
sub
FHEMWEB_calcWeblink($$)
{
my ($d,$wl) = @_;
return if($__plotmode eq "gnuplot");
my $now = time();
my $zoom = $__wlpos{zoom};
$zoom = "day" if(!$zoom);
if(!$d) {
foreach my $d (sort keys %__devs ) {
next if($__devs{$d}{type} ne "weblink");
next if(!$__room || ($__room ne "all" && !$__rooms{$__room}{$d}));
next if($__devs{$d}{ATTR} && $__devs{$d}{ATTR}{noscroll});
next if($__devs{$d}{ATTR} && $__devs{$d}{ATTR}{fixedrange});
$__scrolledweblinkcount++;
}
return;
}
return if(!$__devs{$wl});
return if($__devs{$wl} && $__devs{$wl}{ATTR}{noscroll});
if($__devs{$wl} && $__devs{$wl}{ATTR}{fixedrange}) {
my @range = split(" ", $__devs{$wl}{ATTR}{fixedrange}{VAL});
$__devs{$d}{from} = $range[0];
$__devs{$d}{to} = $range[1];
return;
}
my $off = $__wlpos{$d};
$off = 0 if(!$off);
$off += $__wlpos{all} if($__wlpos{all});
if($zoom eq "day") {
my $t = $now + $off*86400;
my @l = localtime($t);
$__devs{$d}{from} = sprintf("%04d-%02d-%02d",$l[5]+1900,$l[4]+1,$l[3]);
$__devs{$d}{to} = sprintf("%04d-%02d-%02d",$l[5]+1900,$l[4]+1,$l[3]+1);
} elsif($zoom eq "week") {
my @l = localtime($now);
my $t = $now - ($l[6]*86400) + ($off*86400)*7;
@l = localtime($t);
$__devs{$d}{from} = sprintf("%04d-%02d-%02d",$l[5]+1900,$l[4]+1,$l[3]);
@l = localtime($t+7*86400);
$__devs{$d}{to} = sprintf("%04d-%02d-%02d",$l[5]+1900,$l[4]+1,$l[3]);
} elsif($zoom eq "month") {
my @l = localtime($now);
while($off < -12) {
$off += 12; $l[5]--;
}
$l[4] += $off;
$l[4] += 12, $l[5]-- if($l[4] < 0);
$__devs{$d}{from} = sprintf("%04d-%02d", $l[5]+1900, $l[4]+1);
$l[4]++;
$l[4] = 0, $l[5]++ if($l[4] == 12);
$__devs{$d}{to} = sprintf("%04d-%02d", $l[5]+1900, $l[4]+1);
} elsif($zoom eq "year") {
my @l = localtime($now);
$l[5] += $off;
$__devs{$d}{from} = sprintf("%04d", $l[5]+1900);
$__devs{$d}{to} = sprintf("%04d", $l[5]+1901);
}
}
##################
sub sub
pF($@) pF($@)
{ {
@@ -911,12 +1138,14 @@ pF($@)
$__RET .= sprintf $fmt, @_; $__RET .= sprintf $fmt, @_;
} }
##################
sub sub
pO(@) pO(@)
{ {
$__RET .= shift; $__RET .= shift;
} }
##################
sub sub
fC($) fC($)
{ {

View File

@@ -11,6 +11,7 @@ weblink_Initialize($)
my ($hash) = @_; my ($hash) = @_;
$hash->{DefFn} = "weblink_Define"; $hash->{DefFn} = "weblink_Define";
$hash->{AttrList}= "fixedrange noscroll";
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

View File

@@ -19,4 +19,6 @@ set y2tics
set format y "%.1f" set format y "%.1f"
set format y2 "%.1f" set format y2 "%.1f"
#FileLog 0 4::
plot "<IN>" using 1:4 notitle with lines plot "<IN>" using 1:4 notitle with lines

View File

@@ -17,10 +17,15 @@ set grid xtics y2tics
set y2label "temperature (Celsius)" set y2label "temperature (Celsius)"
set ylabel "Actuator (%)" set ylabel "Actuator (%)"
#FileLog 4:measured:
##FileLog 4:desired:
#FileLog 4:actuator.*%:int
# "< awk '/desired/ {print $1, $4+0}' <IN>"\
# using 1:2 axes x1y2 title 'Desired temperature' with steps,\
plot \ plot \
"< awk '/measured/{print $1, $4}' <IN>"\ "< awk '/measured/{print $1, $4}' <IN>"\
using 1:2 axes x1y2 title 'Measured temperature' with lines lw 2,\ using 1:2 axes x1y2 title 'Measured temperature' with lines lw 2,\
"< awk '/desired/ {print $1, $4+0}' <IN>"\
using 1:2 axes x1y2 title 'Desired temperature' with steps,\
"< awk '/actuator/ {print $1, $4+0}' <IN>"\ "< awk '/actuator/ {print $1, $4+0}' <IN>"\
using 1:2 axes x1y1 title 'Actuator (%)' with lines\ using 1:2 axes x1y1 title 'Actuator (%)' with lines\

View File

@@ -17,5 +17,7 @@ set y2range [-0.1:1.1]
set ylabel "Pumpe" set ylabel "Pumpe"
set y2label "Pumpe" set y2label "Pumpe"
#FileLog 3::$fld[2]eq"on"?1:0
plot "< awk '{print $1, $3==\"on\"? 1 : 0; }' <IN>"\ plot "< awk '{print $1, $3==\"on\"? 1 : 0; }' <IN>"\
using 1:2 notitle with steps using 1:2 notitle with steps

View File

@@ -20,6 +20,10 @@ set yrange [0:]
# Computing Rain/h and Rain/d values by accumulating the changes. # Computing Rain/h and Rain/d values by accumulating the changes.
#FileLog 4:IR:
#FileLog 10:IR:delta-h
#FileLog 10:IR:delta-d
plot "<IN>" using 1:4 axes x1y2 title 'Temperature' with lines lw 2,\ plot "<IN>" using 1:4 axes x1y2 title 'Temperature' with lines lw 2,\
"<grep -v avg_ <IN> | perl -ane '\ "<grep -v avg_ <IN> | perl -ane '\
@a = split(\"[_:]\", $F[0]);\ @a = split(\"[_:]\", $F[0]);\

View File

@@ -15,5 +15,9 @@ set grid
set ylabel "Wind (Km/h)" set ylabel "Wind (Km/h)"
set y2label "Humidity (%)" set y2label "Humidity (%)"
#FileLog 8:IR:
#FileLog 6:IR:
plot "<IN>" using 1:8 axes x1y1 title 'Wind' with lines,\ plot "<IN>" using 1:8 axes x1y1 title 'Wind' with lines,\
"<IN>" using 1:6 axes x1y2 title 'Rel. Humidity (%)' with lines "<IN>" using 1:6 axes x1y2 title 'Rel. Humidity (%)' with lines

View File

@@ -16,5 +16,8 @@ set grid
set ylabel "Temperature (Celsius)" set ylabel "Temperature (Celsius)"
set y2label "Rain (l/m2)" set y2label "Rain (l/m2)"
#FileLog 5:avg_day:
#FileLog 11:avg_day:
plot "<grep avg_day <IN>" using 1:5 axes x1y1 title 'Temperature' with lines,\ plot "<grep avg_day <IN>" using 1:5 axes x1y1 title 'Temperature' with lines,\
"<grep avg_day <IN>" using 1:11 axes x1y2 title 'Rain' with histeps "<grep avg_day <IN>" using 1:11 axes x1y2 title 'Rain' with histeps

View File

@@ -15,6 +15,12 @@ set ytics ("Sz" 0.8, "FlO" 0.6, "FlU" 0.4, "Wz1" 0.2, "Wz2" 0.0)
set y2tics ("Sz" 0.8, "FlO" 0.6, "FlU" 0.4, "Wz1" 0.2, "Wz2" 0.0) set y2tics ("Sz" 0.8, "FlO" 0.6, "FlU" 0.4, "Wz1" 0.2, "Wz2" 0.0)
set yrange [-0.1:0.9] set yrange [-0.1:0.9]
#FileLog "0.8":sz:
#FileLog "0.6":flo:
#FileLog "0.4":flu:
#FileLog "0.2":wz1:
#FileLog "0.0":wz2:
plot\ plot\
"< awk '/sz/ {print $1, 0.8; }' <IN>" using 1:2 notitle with points,\ "< awk '/sz/ {print $1, 0.8; }' <IN>" using 1:2 notitle with points,\
"< awk '/flo/{print $1, 0.6; }' <IN>" using 1:2 notitle with points,\ "< awk '/flo/{print $1, 0.6; }' <IN>" using 1:2 notitle with points,\

View File

@@ -13,5 +13,7 @@ set title '<TL>'
set grid set grid
set yrange [-0.2:1.2] set yrange [-0.2:1.2]
#FileLog "1":::
plot "< awk '{print $1, $3==\"on\"? 1 : 0; }' <IN>"\ plot "< awk '{print $1, $3==\"on\"? 1 : 0; }' <IN>"\
using 1:2 title 'On/Off' with impulses using 1:2 title 'On/Off' with impulses

View File

@@ -0,0 +1,145 @@
body {
color: black;
background: #FFFFD7;
}
table.room {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #D7FFFF;
}
table.room tr.sel {
background: #A0FFFF;
}
table.FS20 {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #C0FFFF;
}
table.FS20 tr.odd {
background: #D7FFFF;
}
table.FHT {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #FFC0C0;
}
table.FHT tr.odd {
background: #FFD7D7;
}
table.KS300 {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #C0FFC0;
}
table.KS300 tr.odd {
background: #A7FFA7;
}
table.FileLog {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #FFC0C0;
}
table.FileLog tr.odd {
background: #FFD7D7;
}
table.at {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #FFFFC0;
}
table.at tr.odd {
background: #FFFFD7;
}
table.notify {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #D7D7A0;
}
table.notify tr.odd {
background: #FFFFC0;
}
table.FHZ {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #C0C0C0;
}
table.FHZ tr.odd {
background: #D7D7D7;
}
table.EM {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #E0E0E0;
}
table.EM tr.odd {
background: #F0F0F0;
}
table._internal_ {
border: solid;
border-width: thin;
width: 100%;
-moz-border-radius:8px;
background: #C0C0C0;
}
table._internal_ tr.odd {
background: #D7D7D7;
}
#hdr {
position:absolute;
top:10px;
left:10px;
}
#left {
position:absolute;
top:50px;
left:10px;
width:130px;
}
#right {
position:absolute;
top:50px;
left:160px;
bottom:10px;
overflow:auto;
}