mirror of
https://github.com/skaringa/water-counter.git
synced 2024-11-21 17:04:25 +01:00
Website added
This commit is contained in:
parent
8a3a787351
commit
b41b81c9f4
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
*~
|
||||||
|
*.bak
|
||||||
|
*.rrd
|
||||||
|
nohup.out
|
||||||
|
*.gif
|
||||||
|
minicom.cap
|
2
graph.sh
2
graph.sh
@ -2,7 +2,7 @@
|
|||||||
rrdtool graph counter.gif \
|
rrdtool graph counter.gif \
|
||||||
-s 'now -1 day' -e 'now' \
|
-s 'now -1 day' -e 'now' \
|
||||||
-w 800 -h 600 \
|
-w 800 -h 600 \
|
||||||
-X 0 -A \
|
-A -Y \
|
||||||
DEF:counter=water.rrd:counter:LAST \
|
DEF:counter=water.rrd:counter:LAST \
|
||||||
VDEF:lastcount=counter,LAST \
|
VDEF:lastcount=counter,LAST \
|
||||||
"GPRINT:lastcount:%6.3lf m³" \
|
"GPRINT:lastcount:%6.3lf m³" \
|
||||||
|
119
www/graph.pl
Executable file
119
www/graph.pl
Executable file
@ -0,0 +1,119 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# CGI script to create image using RRD graph
|
||||||
|
use CGI qw(:all);
|
||||||
|
use RRDs;
|
||||||
|
use POSIX qw(locale_h);
|
||||||
|
|
||||||
|
$ENV{'LANG'}='de_DE.UTF-8';
|
||||||
|
setlocale(LC_ALL, 'de_DE.UTF-8');
|
||||||
|
|
||||||
|
# path to database
|
||||||
|
$rrd='../../water-counter/water.rrd';
|
||||||
|
|
||||||
|
# force to always create image from rrd
|
||||||
|
#$force=1;
|
||||||
|
|
||||||
|
$query=new CGI;
|
||||||
|
#$query=new CGI("type=consumweek&size=small");
|
||||||
|
|
||||||
|
$size=$query->param('size');
|
||||||
|
$type=$query->param('type');
|
||||||
|
if ($size eq 'big') {
|
||||||
|
$width=900;
|
||||||
|
$height=700;
|
||||||
|
$size="b";
|
||||||
|
} else {
|
||||||
|
$width=500;
|
||||||
|
$height=160;
|
||||||
|
$size="s";
|
||||||
|
}
|
||||||
|
die "invalid type\n" unless $type =~ /(count|consum)(day|week|month|year)/;
|
||||||
|
$ds=$1;
|
||||||
|
$range=$2;
|
||||||
|
$filename="/tmp/em${type}_${size}.png";
|
||||||
|
|
||||||
|
# create new image if existing file is older than rrd file
|
||||||
|
my $maxdiff = 10;
|
||||||
|
if ((mtime($rrd) - mtime($filename) > $maxdiff) or $force) {
|
||||||
|
$tmpfile="/tmp/wai${type}_${size}_$$.png";
|
||||||
|
# call sub to create image according to type
|
||||||
|
&$ds($range);
|
||||||
|
# check error
|
||||||
|
my $err=RRDs::error;
|
||||||
|
die "$err\n" if $err;
|
||||||
|
rename $tmpfile, $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
# feed image to stdout
|
||||||
|
open(IMG, $filename) or die "can't open $filename";
|
||||||
|
print header('image/png');
|
||||||
|
print <IMG>;
|
||||||
|
close IMG;
|
||||||
|
|
||||||
|
# end MAIN
|
||||||
|
|
||||||
|
# Return modification date of file
|
||||||
|
sub mtime {
|
||||||
|
my $file=shift;
|
||||||
|
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$fsize,
|
||||||
|
$atime,$mtime,$ctime,$blksize,$blocks)
|
||||||
|
= stat($file);
|
||||||
|
return $mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub count {
|
||||||
|
my $range = shift;
|
||||||
|
my @opts=(
|
||||||
|
"-w", $width,
|
||||||
|
"-h", $height,
|
||||||
|
"-s", "now - 1 $range",
|
||||||
|
"-e", "now",
|
||||||
|
"-D",
|
||||||
|
"-Y",
|
||||||
|
"-A");
|
||||||
|
RRDs::graph($tmpfile,
|
||||||
|
@opts,
|
||||||
|
"DEF:counter=$rrd:counter:LAST",
|
||||||
|
"LINE2:counter#000000:Zähler",
|
||||||
|
"VDEF:countlast=counter,LAST",
|
||||||
|
"GPRINT:countlast:%.3lf m³"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub consum {
|
||||||
|
my $range = shift;
|
||||||
|
my @opts=(
|
||||||
|
"-w", $width,
|
||||||
|
"-h", $height,
|
||||||
|
"-D",
|
||||||
|
"-Y",
|
||||||
|
"-A",
|
||||||
|
"-e", "now",
|
||||||
|
"-s"
|
||||||
|
);
|
||||||
|
if ($range eq 'month') {
|
||||||
|
push(@opts, "now - 30 days");
|
||||||
|
} else {
|
||||||
|
push(@opts, "now - 1 $range");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($range eq 'day') {
|
||||||
|
RRDs::graph($tmpfile,
|
||||||
|
@opts,
|
||||||
|
"DEF:consum=$rrd:consum:AVERAGE",
|
||||||
|
"CDEF:conlpmin=consum,60000,*",
|
||||||
|
"CDEF:conlpd=conlpmin,60,*,24,*",
|
||||||
|
"VDEF:conlpdtotal=conlpd,AVERAGE",
|
||||||
|
"GPRINT:conlpdtotal:Total %4.0lf l/d",
|
||||||
|
"LINE2:conlpmin#00FF00:Verbrauch [l/min]"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
RRDs::graph($tmpfile,
|
||||||
|
@opts,
|
||||||
|
"DEF:consum=$rrd:consum:AVERAGE",
|
||||||
|
"CDEF:conlpd=consum,60000,*,60,*,24,*",
|
||||||
|
"LINE2:conlpd#00FF00:l/d"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
105
www/index.html
Normal file
105
www/index.html
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="initial-scale=1, minimum-scale=0.75, width=device-width"/>
|
||||||
|
<title>Wasserverbrauch</title>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
// <![CDATA[
|
||||||
|
|
||||||
|
// open table popup window
|
||||||
|
function table(href) {
|
||||||
|
window.open(href, 'table', 'width=400,height=500,scrollbars=yes');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// open graph popup window
|
||||||
|
function graph(href) {
|
||||||
|
window.open(href, 'graph', 'width=950,height=750,scrollbars=no');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// initialize the page
|
||||||
|
function init() {
|
||||||
|
// reload after 5 min
|
||||||
|
window.setTimeout("window.location.reload(true)", 5 * 60 * 1000);
|
||||||
|
}
|
||||||
|
// ]]>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
body, table, form {
|
||||||
|
font: 10px/16px verdana, arial, helvetica, sans-serif;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.datatable {
|
||||||
|
width: 500px;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
img.graph {
|
||||||
|
width: 500px;
|
||||||
|
height: 160px;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
border-width: 0px 0px 1px 0px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #998DB3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body onload="init()">
|
||||||
|
|
||||||
|
<table class="datatable">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<h2>Wasserverbrauch</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img alt="Zählerstand (24 h)" id="i0l" class="graph" src="graph.pl?type=countday" title="Zählerstand (24 h)"/>
|
||||||
|
<br/>
|
||||||
|
<a href="graph.pl?type=countday&size=big" onclick="return graph(this.href);">Vergrößern</a>
|
||||||
|
| <a href="table.pl?type=countday" onclick="return table(this.href);" target="table">Tabelle</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img alt="Verbrauch (24 h)" id="i1l" class="graph" src="graph.pl?type=consumday" title="Verbrauch (24 h)"/>
|
||||||
|
<br/>
|
||||||
|
<a href="graph.pl?type=consumday&size=big" onclick="return graph(this.href);" >Vergrößern</a>
|
||||||
|
| <a href="table.pl?type=consumday" onclick="return table(this.href);" target="table">Tabelle</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img alt="Verbrauch (Woche)" id="i2l" class="graph" src="graph.pl?type=consumweek" title="Verbrauch (Woche)"/>
|
||||||
|
<br/>
|
||||||
|
<a href="graph.pl?type=consumweek&size=big" onclick="return graph(this.href);" >Vergrößern</a>
|
||||||
|
| <a href="table.pl?type=consumweek" onclick="return table(this.href);" target="table">Tabelle</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img alt="Verbrauch (Monat)" id="i3l" class="graph" src="graph.pl?type=consummonth" title="Verbrauch (Monat)"/>
|
||||||
|
<br/>
|
||||||
|
<a href="graph.pl?type=consummonth&size=big" onclick="return graph(this.href);" >Vergrößern</a>
|
||||||
|
| <a href="table.pl?type=consummonth" onclick="return table(this.href);" target="table">Tabelle</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img alt="Verbrauch (Jahr)" id="i4l" class="graph" src="graph.pl?type=consumyear" title="Verbrauch (Jahr)"/>
|
||||||
|
<br/>
|
||||||
|
<a href="graph.pl?type=consumyear&size=big" onclick="return graph(this.href);" >Vergrößern</a>
|
||||||
|
| <a href="table.pl?type=consumyear" onclick="return table(this.href);" target="table">Tabelle</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
150
www/table.pl
Executable file
150
www/table.pl
Executable file
@ -0,0 +1,150 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# CGI script to create a table of values from RRD
|
||||||
|
use CGI qw(:all *table *Tr);
|
||||||
|
use RRDs;
|
||||||
|
use POSIX qw(strftime);
|
||||||
|
use POSIX qw(locale_h);
|
||||||
|
|
||||||
|
$ENV{'LANG'}='de_DE.UTF-8';
|
||||||
|
setlocale(LC_TIME, 'de_DE.UTF-8');
|
||||||
|
|
||||||
|
# path to database
|
||||||
|
$rrdb='../../water-counter/water.rrd';
|
||||||
|
|
||||||
|
$query=new CGI;
|
||||||
|
#$query=new CGI("type=consumweek");
|
||||||
|
|
||||||
|
print header(-charset=>"utf-8");
|
||||||
|
|
||||||
|
$type=$query->param('type');
|
||||||
|
if ($type !~ /(count|consum)(day|week|month|year)/) {
|
||||||
|
print "Invalid type\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$sensor=$1;
|
||||||
|
$range=$2;
|
||||||
|
|
||||||
|
#print "Sensor: $sensor Range: $range\n";
|
||||||
|
|
||||||
|
$timeformat="%a, %d. %b %Y";
|
||||||
|
$resolution=24*60*60;
|
||||||
|
if ($range eq 'day') {
|
||||||
|
$resolution=60*60;
|
||||||
|
$timeformat="%a, %d. %b %Y %H:%M";
|
||||||
|
} elsif ($range eq 'year') {
|
||||||
|
$resolution=7*24*60*60;
|
||||||
|
$timeformat="Wo %d. %b %Y";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($range eq 'day') {
|
||||||
|
@factors = (1.0, 60000.0); # consumption in l/min
|
||||||
|
@headings = ('m³', 'l/min');
|
||||||
|
@formats = ('%7.3f', '%3.1f');
|
||||||
|
} else {
|
||||||
|
@factors = (1.0, 60000.0*60*24); # consumption l/day
|
||||||
|
@headings = ('m³', 'l/d');
|
||||||
|
@formats = ('%7.3f', '%4.0f');
|
||||||
|
}
|
||||||
|
|
||||||
|
($laststart,$laststep,$lastnames,$lastdata) = getdata($rrdb, 'LAST', $resolution, $range);
|
||||||
|
($avrstart,$avrstep,$avrnames,$avrdata) = getdata($rrdb, 'AVERAGE', $resolution, $range);
|
||||||
|
# print result
|
||||||
|
|
||||||
|
# print heading
|
||||||
|
$style=<<END;
|
||||||
|
<!--
|
||||||
|
body {
|
||||||
|
font: 10px/16px verdana, arial, helvetica, sans-serif;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
border-width: 1px 1px 0px 0px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #998DB3;
|
||||||
|
text-align: right;
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: lightgreen;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
thead {
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
tbody {
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
.mindata {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
.maxdata {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
color: black;
|
||||||
|
text-align: left;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
-->
|
||||||
|
END
|
||||||
|
|
||||||
|
print start_html(-title=>"Wasserverbrauch",
|
||||||
|
-style=>{-code=>$style},
|
||||||
|
-meta=>{"viewport"=>"initial-scale=1, minimum-scale=0.75, width=device-width"}
|
||||||
|
);
|
||||||
|
print start_table();
|
||||||
|
print "\n";
|
||||||
|
print thead(Tr(th({-class=>'time'}, ' '), th([@headings])));
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
# print data
|
||||||
|
$avrstart -= 12*60*60 unless $timeformat =~ / %H:%M$/;
|
||||||
|
for $avrline (@$avrdata) {
|
||||||
|
$lastline = shift(@$lastdata);
|
||||||
|
print start_Tr({-class=>'avrdata'});
|
||||||
|
print td({-class=>'time'}, strftime($timeformat, localtime($avrstart)));
|
||||||
|
print formatline(@$lastline[0], @$avrline[1]);
|
||||||
|
print end_Tr;
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
$avrstart += $avrstep;
|
||||||
|
}
|
||||||
|
print end_table();
|
||||||
|
print end_html;
|
||||||
|
|
||||||
|
sub getdata {
|
||||||
|
my ($db, $cf, $resolution, $range) = @_;
|
||||||
|
|
||||||
|
my $sarg = "now -1 $range";
|
||||||
|
if ($range eq 'month') {
|
||||||
|
$sarg = "now - 30 days";
|
||||||
|
}
|
||||||
|
my ($start,$step,$names,$data) = RRDs::fetch($db, $cf, '-r', $resolution, '-s', $sarg, '-e', 'now');
|
||||||
|
|
||||||
|
# check error
|
||||||
|
my $err=RRDs::error;
|
||||||
|
print "$err\n" if $err;
|
||||||
|
exit if $err;
|
||||||
|
return ($start,$step,$names,$data);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub formatline {
|
||||||
|
my $str = '';
|
||||||
|
my $i = 0;
|
||||||
|
for $val (@_) {
|
||||||
|
if (defined $val) {
|
||||||
|
$str .= td(sprintf $formats[$i], $val * $factors[$i]);
|
||||||
|
} else {
|
||||||
|
$str .= td;
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user