% my $url = url_for 'weather';
+% my $s;
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Latest compiled and minified CSS -->
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
+ <link rel="stylesheet" href="css/bootstrap.min.css">
<!-- Optional theme -->
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
+ <link rel="stylesheet" href="css/bootstrap-theme.min.css">
</head>
<body>
<script>
var ws;
- var day_chart;
+ var daychart;
+ var daychart_days = <%= $main::histdays %>;
+ var windrose;
+ var windrose_mins = <%= $main::windmins %>;
+ var windspeed;
+ var winddir;
+ var updatespermin = <%= $main::updatepermin %>;
var h = new Object();
+ var trans = {
+ "Wind" : function (speed) { return (speed * 2.236936).toFixed(1); },
+ "Wind_1m" : function (speed) { return (speed * 2.236936).toFixed(1); },
+ "Wind_Max": function (speed) { return (speed * 2.236936).toFixed(1); }
+ };
+
+
function do_debug(text) {
document.getElementById("do_debug").innerHTML = text;
}
function fill_html(key,value) {
var d = document.getElementById(key);
if (d !== null) {
- d.innerHTML = value;
+ var f = trans[key];
+ if (f && typeof(f) === "function") {
+ d.innerHTML = trans[key](value);
+ } else {
+ d.innerHTML = value;
+ }
}
}
}
}
+ var lastwind = 0;
+ var lastdir = 0;
+ var lastt = 0;
+
function startws() {
ws = new WebSocket('<%= $url->to_abs %>');
var js = JSON.parse(event.data);
if (js !== null && typeof(js) === 'object') {
traverse(js, fill_html);
- traverse(js, update_h);
- document.getElementById("hh").innerHTML = JSON.stringify(h);
+// traverse(js, update_h);
+// document.getElementById("hh").innerHTML = JSON.stringify(h);
if ("h" in js) {
- fill_day_chart(js);
+ fill_daychart(js, daychart_days);
+ }
+ if ("r" in js || "m" in js) {
+ var rr;
+ rr = js.r || js.m;
+ if (!("Dir" in rr))
+ rr.Dir = lastdir;
+ if (!("Wind" in rr))
+ rr.Wind = lastwind;
+ fill_windrose(rr, windrose_mins * updatespermin);
+ fill_windspeed(rr);
+ fill_winddir(rr);
+ lastwind = rr.Wind;
+ lastdir = rr.Dir;
}
}
};
}
}
- function start_day_chart() {
- day_chart = new Highcharts.Chart({
+ function start_daychart() {
+ daychart = new Highcharts.Chart({
chart: {
- renderTo: 'day_chart',
+ renderTo: 'daychart',
zoomType: 'xy'
},
title: {
- text: '24 Hour Chart'
+ text: 'Five Day Chart'
},
xAxis: [{
type: 'datetime',
labels: {
format: '{value}°C',
style: {
- color: Highcharts.getOptions().colors[2]
+ color: '#ff0000'
}
},
title: {
text: 'Temperature',
style: {
- color: Highcharts.getOptions().colors[2]
+ color: '#ff0000'
}
},
opposite: true
}
},
opposite: true
+ }, { // Tertiary yAxis
+ gridLineWidth: 0,
+ floor: 0,
+ ceiling: 100,
+ title: {
+ text: 'Humidity',
+ style: {
+ color: '#008800'
+ }
+ },
+ labels: {
+ format: '{value} %',
+ style: {
+ color: '#008800'
+ }
+ },
+// opposite: true
}],
tooltip: {
shared: true
legend: {
layout: 'vertical',
align: 'left',
- x: 80,
+ x: 120,
verticalAlign: 'top',
y: 55,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
},
+ exporting: {
+ buttons: {
+ contextButton: {
+ enabled: false
+ }
+ }
+ },
series: [{
name: 'Rainfall',
type: 'column',
yAxis: 1,
- data: [],
+ labels: {
+// enabled: true,
+// format: '{point.y:.1f}', // one decimal
+// rotation: -90,
+ overflow: 'justify'
+ },
+ data: [
+ <% $s = "";
+ for (@main::last5daysh) {
+ my $r = $main::json->decode($_);
+ $s .= "[" . $r->{t}*1000 . "," . $r->{h}->{Rain_1h} . "]," if $r && exists $r->{t} && exists $r->{h}->{Rain_1h};
+ }
+ chop $s if length $s;
+ %><%= $s %>
+ ],
tooltip: {
valueSuffix: ' mm'
}
name: 'Sea-Level Pressure',
type: 'spline',
yAxis: 2,
- data: [],
+ data: [
+ <% $s = "";
+ for (@main::last5daysh) {
+ my $r = $main::json->decode($_);
+ $s .= "[" . $r->{t}*1000 . "," . $r->{h}->{Pressure} . "]," if $r && exists $r->{t} && exists $r->{h}->{Pressure};
+ }
+ chop $s if length $s;
+ %><%= $s %>
+ ],
marker: {
enabled: false
},
}, {
name: 'Temperature',
type: 'spline',
- data: [],
+ yAxis: 0,
+ color: '#ff0000',
+ data: [
+ <% $s = "";
+ for (@main::last5daysh) {
+ my $r = $main::json->decode($_);
+ $s .= "[" . $r->{t}*1000 . "," . $r->{h}->{Temp_Out} . "]," if $r && exists $r->{t} && exists $r->{h}->{Temp_Out};
+ }
+ chop $s if length $s;
+ %><%= $s %>
+ ],
tooltip: {
valueSuffix: ' °C'
}
+ }, {
+ name: 'Humidity',
+ type: 'spline',
+ color: '#008800',
+ yAxis: 3,
+ data: [
+ <% $s = "";
+ for (@main::last5daysh) {
+ my $r = $main::json->decode($_);
+ $s .= "[" . $r->{t}*1000 . "," . $r->{h}->{Humidity_Out} . "]," if $r && exists $r->{t} && exists $r->{h}->{Humidity_Out};
+ }
+ chop $s if length $s;
+ %><%= $s %>
+ ],
+ marker: {
+ enabled: false
+ },
+ dashStyle: 'shortdot',
+ tooltip: {
+ valueSuffix: ' %'
+ }
}]
});
}
- function fill_day_chart(js) {
- var rainfall = day_chart.series[0].data.length > 48;
- var pressure = day_chart.series[1].data.length > 48;
- var temp = day_chart.series[2].data.length > 48;
+ function start_windrose() {
+
+ // Load the fonts
+ Highcharts.createElement('link', {
+ href: '//fonts.googleapis.com/css?family=Dosis:400,600',
+ rel: 'stylesheet',
+ type: 'text/css'
+ }, null, document.getElementsByTagName('head')[0]);
+
+ Highcharts.theme = {
+ colors: ["#7cb5ec", "#f7a35c", "#90ee7e", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee",
+ "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
+ chart: {
+ backgroundColor: null,
+ style: {
+ fontFamily: "Dosis, sans-serif"
+ }
+ },
+ title: {
+ style: {
+ fontSize: '16px',
+ fontWeight: 'bold',
+ textTransform: 'uppercase'
+ }
+ },
+ tooltip: {
+ borderWidth: 0,
+ backgroundColor: 'rgba(219,219,216,0.8)',
+ shadow: false
+ },
+ legend: {
+ itemStyle: {
+ fontWeight: 'bold',
+ fontSize: '13px'
+ }
+ },
+ xAxis: {
+ gridLineWidth: 1,
+ labels: {
+ style: {
+ fontSize: '12px'
+ }
+ }
+ },
+ yAxis: {
+ minorTickInterval: 'auto',
+ title: {
+ style: {
+ textTransform: 'uppercase'
+ }
+ },
+ labels: {
+ style: {
+ fontSize: '12px'
+ }
+ }
+ },
+ plotOptions: {
+ candlestick: {
+ lineColor: '#404048'
+ }
+ },
+
+
+ // General
+ background2: '#F0F0EA'
+
+ };
+
+ // Apply the theme
+ Highcharts.setOptions(Highcharts.theme);
+
+ windrose = new Highcharts.Chart({
+ chart: {
+ polar: true,
+ renderTo: 'windrose'
+ },
+
+ title: {
+ text: 'Wind Rose'
+ },
+
+ pane: {
+ startAngle: 0,
+ endAngle: 360
+ },
+
+ xAxis: {
+ tickInterval: 15,
+ min: 0,
+ max: 360,
+ labels: {
+ formatter: function () {
+ return this.value + '°';
+ }
+ }
+ },
+
+ yAxis: {
+ min: 0
+ },
+
+ plotOptions: {
+ series: {
+ pointStart: 0,
+ pointInterval: 15
+ },
+ column: {
+ pointPadding: 0,
+ groupPadding: 0
+ }
+ },
+ exporting: {
+ buttons: {
+ contextButton: {
+ enabled: false
+ }
+ }
+ },
+
+ series: [ {
+ type: 'scatter',
+ name: 'Wind mph',
+ data: [
+ <% my ($d, $w);
+ $s = "";
+ $d = 0; $w = 0;
+ for (@main::last10minsr) {
+ my $r = $main::json->decode($_);
+ if ($r) {
+ $r->{r}->{Dir} ||= $d;
+ $r->{r}->{Wind} ||= $w;
+ $s .= "[" . $r->{r}->{Dir} . "," . main::nearest(0.1, $r->{r}->{Wind}*2.23694) . "],";
+ $d = $r->{r}->{Dir};
+ $w = $r->{r}->{Wind};
+ }
+ }
+ chop $s if length $s;
+ %><%= $s %>
+ ]
+ }]
+ });
+ }
+
+ function start_windspeed() {
+ windspeed = new Highcharts.Chart({
+ chart: {
+ type: 'gauge',
+ renderTo: 'windspeed',
+ plotBackgroundColor: null,
+ plotBackgroundImage: null,
+ plotBorderWidth: 0,
+ plotShadow: false
+ },
+
+ title: {
+ text: 'Wind Speed'
+ },
+
+ pane: {
+ startAngle: -150,
+ endAngle: 150,
+ background: [{
+ backgroundColor: {
+ linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
+ stops: [
+ [0, '#FFF'],
+ [1, '#333']
+ ]
+ },
+ borderWidth: 0,
+ outerRadius: '109%'
+ }, {
+ backgroundColor: {
+ linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
+ stops: [
+ [0, '#333'],
+ [1, '#FFF']
+ ]
+ },
+ borderWidth: 1,
+ outerRadius: '107%'
+ }, {
+ // default background
+ }, {
+ backgroundColor: '#DDD',
+ borderWidth: 0,
+ outerRadius: '105%',
+ innerRadius: '103%'
+ }]
+ },
+
+ // the value axis
+ yAxis: {
+ min: 0,
+ max: 50,
+
+ minorTickInterval: 'auto',
+ minorTickWidth: 1,
+ minorTickLength: 10,
+ minorTickPosition: 'inside',
+ minorTickColor: '#666',
+
+ tickPixelInterval: 30,
+ tickWidth: 2,
+ tickPosition: 'inside',
+ tickLength: 10,
+ tickColor: '#666',
+ labels: {
+ step: 2,
+ rotation: 'auto'
+ },
+ title: {
+ text: 'mph'
+ },
+ plotBands: [{
+ from: 0,
+ to: 15,
+ color: '#55BF3B' // green
+ }, {
+ from: 16,
+ to: 29,
+ color: '#DDDF0D' // yellow
+ }, {
+ from: 30,
+ to: 50,
+ color: '#DF5353' // red
+ }]
+ },
+ exporting: {
+ buttons: {
+ contextButton: {
+ enabled: false
+ }
+ }
+ },
+
+ series: [{
+ name: 'Speed',
+ data: [0],
+ tooltip: {
+ valueSuffix: ' mph'
+ }
+ }]
+ });
+ }
+
+ function start_winddir() {
+ winddir = new Highcharts.Chart({
+ chart: {
+ type: 'gauge',
+ renderTo: 'winddir',
+ plotBackgroundColor: null,
+ plotBackgroundImage: null,
+ plotBorderWidth: 0,
+ plotShadow: false
+ },
+
+ title: {
+ text: 'Wind Direction'
+ },
+
+ pane: {
+ startAngle: 0,
+ endAngle: 360,
+ background: [{
+ backgroundColor: {
+ linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
+ stops: [
+ [0, '#FFF'],
+ [1, '#333']
+ ]
+ },
+ borderWidth: 0,
+ outerRadius: '109%'
+ }, {
+ backgroundColor: {
+ linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
+ stops: [
+ [0, '#333'],
+ [1, '#FFF']
+ ]
+ },
+ borderWidth: 1,
+ outerRadius: '107%'
+ }, {
+ // default background
+ }, {
+ backgroundColor: '#DDD',
+ borderWidth: 0,
+ outerRadius: '105%',
+ innerRadius: '103%'
+ }]
+ },
+
+ // the value axis
+ yAxis: {
+ min: 0,
+ max: 359,
+
+ minorTickInterval: 'auto',
+ minorTickWidth: 1,
+ minorTickLength: 10,
+ minorTickPosition: 'inside',
+ minorTickColor: '#666',
+
+ tickPixelInterval: 15,
+ tickWidth: 2,
+ tickPosition: 'inside',
+ tickLength: 10,
+ tickColor: '#666',
+ labels: {
+ step: 2,
+ rotation: 'auto'
+ },
+ title: {
+ text: '° deg'
+ },
+ },
+ exporting: {
+ buttons: {
+ contextButton: {
+ enabled: false
+ }
+ }
+ },
+
+ series: [{
+ name: 'Direction',
+ data: [0],
+ tooltip: {
+ valueSuffix: ' ° deg'
+ }
+ }]
+ });
+ }
+
+ function fill_daychart(js, days) {
+ var rainfall = daychart.series[0].data.length > (days * 48);
+ var pressure = daychart.series[1].data.length > (days * 48);
+ var temp = daychart.series[2].data.length > (days * 48);
+ var humidity = daychart.series[3].data.length > (days * 48);
var hr = js.h;
var t = js.t * 1000;
var ra = [t, hr.Rain_1h];
var pr = [t, hr.Pressure];
var te = [t, hr.Temp_Out];
+ var hu = [t, hr.Humidity_Out];
- do_debug(js.tm + " " + t + " " + te + "<br>");
- day_chart.series[0].addPoint(ra, true, rainfall);
- day_chart.series[1].addPoint(pr, true, pressure);
- day_chart.series[2].addPoint(te, true, temp);
+// do_debug(js.tm + " " + t + " " + te + "<br>");
+ daychart.series[0].addPoint(ra, true, rainfall);
+ daychart.series[1].addPoint(pr, true, pressure);
+ daychart.series[2].addPoint(te, true, temp);
+ daychart.series[3].addPoint(hu, true, humidity);
+ }
+
+ var conv = 2.23694;
+
+ function fill_windrose(rr, points) {
+ var p = windrose.series[0].data.length > points;
+ var v = [rr.Dir, (rr.Wind*conv)];
+ windrose.series[0].addPoint(v, true, p);
+ }
+
+ function fill_windspeed(rr) {
+ var point = windspeed.series[0].points[0];
+ point.update(Math.round(rr.Wind*conv));
+ }
+
+ function fill_winddir(rr) {
+ var point = winddir.series[0].points[0];
+ point.update(rr.Dir);
}
window.onload = function() {
startws();
- start_day_chart();
+ start_daychart();
+ start_windrose();
+ start_windspeed();
+ start_winddir();
window.setInterval(function() {
if (ws === null)
startws();
</script>
+ <div id="container">
+ <div id="daychart" style="min-width: 400px; height: 400px; margin: 0 auto"> </div>
+ </div>
+
+ <div id="container">
+ <table border="0" align="center">
+ <tr>
+ <td id="windrose" style="min-width: 350px; max-width: 400px; height: 330px; margin: 0 auto"> </td>
+ <td id="windspeed" style="min-width: 280px; max-width: 400px; height: 270px; margin: 0 auto"> </td>
+ <td id="winddir" style="min-width: 280px; max-width: 400px; height: 270px; margin: 0 auto"> </td>
+ </tr>
+ </table>
+ </div>
+
<div id="container">
<div id="start-template">
<br><br>
- <table border=1 width=80% align="center">
+ <table class="table">
<tr>
- <th>Time:</th><td><span id="tm"> </span></td>
- <th>Sunrise:</th><td><span id="Sunrise"> </span></td>
- <th>Sunset:</th><td><span id="Sunset"> </span></td>
- <th>Console Volts:</th><td><span id="Batt_Console"> </span></td>
- <th>TX Battery OK:</th><td><span id="Batt_TX_OK"> </span></td>
+ <th width="7%">Time:</th><td width="7%"><span id="tm"> </span></td>
+ <th width="7%">Sunrise:</th><td width="7%"><span id="Sunrise"> </span></td>
+ <th width="7%">Sunset:</th><td width="7%"><span id="Sunset"> </span></td>
+ <th width="7%">Console Volts:</th><td width="7%"><span id="Batt_Console"> </span></td>
+ <th width="7%">TX Battery OK:</th><td width="7%"><span id="Batt_TX_OK"> </span></td>
</tr>
<tr>
- <th>Pressure:</th><td><span id="Pressure"> </span></td>
+ <th>Pressure:</th><td><span id="Pressure"> </span> mb</td>
<th>Trend:</th><td><span id="Pressure_Trend_txt"> </span></td>
</tr>
<tr>
- <th>Temperature in:</th><td> <span id="Temp_In"> </span></td>
- <th>Humidity:</th><td> <span id="Humidity_In"> </span></td>
+ <th>Temperature in:</th><td> <span id="Temp_In"> </span> °C</td>
+ <th>Humidity:</th><td> <span id="Humidity_In"> </span> %</td>
</tr>
- <tr>
- <th>Temperature out:</th><td> <span id="Temp_Out"> </span></td>
- <th>Min:</th><td> <span id="Temp_Out_Min"> </span> @ <span id="Temp_Out_Min_T"> </span></td>
- <th>Max:</th><td> <span id="Temp_Out_Max"> </span> @ <span id="Temp_Out_Max_T"> </span></td>
- <th>Humidity:</th><td> <span id="Humidity_Out"> </span></td>
- <th>Dew Point:</th><td> <span id="Dew_Point"> </span></td>
+ <tr><th>Temperature out:</th><td> <span id="Temp_Out"> </span> °C</td>
+ <th>Min:</th><td> <span id="Temp_Out_Min"> </span> °C @ <span id="Temp_Out_Min_T"> </span></td>
+ <th>Max:</th><td> <span id="Temp_Out_Max"> </span> °C @ <span id="Temp_Out_Max_T"> </span></td>
+ <th>Humidity:</th><td> <span id="Humidity_Out"> </span> %</td>
+ <th>Dew Point:</th><td> <span id="Dew_Point"> </span> °C</td>
</tr>
- <tr>
- <th>Wind Direction:</th><td> <span id="Dir"> </span></td>
- <th>Minute Avg:</th><td> <span id="Dir_1m"> </span></td>
- <th>Speed:</th><td> <span id="Wind"> </span></td>
- <th>Minute Avg:</th><td> <span id="Wind_1m"> </span></td>
+ <tr><th>Wind:</th><td><span id="Dir"> </span> ° @ <span id="Wind"> </span> mph</td>
+ <th>Wind Minute Avg:</th><td> <span id="Dir_1m"> </span> ° @ <span id="Wind_1m"> </span> mph </td>
+ <th>Day Max Speed:</th><td> <span id="Wind_Max"> </span> mph @ <span id="Wind_Max_T"> </span></td>
</tr>
<tr>
- <th>Rain 30mins:</th><td> <span id="Rain_1h"> </span></td>
- <th>Day:</th><td> <span id="Rain_Day"> </span></td>
- <th>24hrs:</th><td> <span id="Rain_24h"> </span></td>
- <th>Month:</th><td> <span id="Rain_Month"> </span></td>
- <th>Year:</th><td> <span id="Rain_Year"> </span></td>
+ <th>Rain 30mins:</th><td> <span id="Rain_1h"> </span> mm</td>
+ <th>Day:</th><td> <span id="Rain_Day"> </span> mm</td>
+ <th>24hrs:</th><td> <span id="Rain_24h"> </span> mm</td>
+ <th>Month:</th><td> <span id="Rain_Month"> </span> mm</td>
+ <th>Year:</th><td> <span id="Rain_Year"> </span> mm</td>
</tr>
</table>
- <br>
- <div id="wsconnect" align="center"> </div>
- <br>
- <div id="hh" align="center"> </div>
</div>
</div>
- <div id="container">
- <div id="day_chart" style="min-width: 400px; height: 400px; margin: 0 auto">
- </div>
- </div>
-
- <div id="container">
- <center><div id="do_debug"> </div></center>
- </div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
+ <script src="js/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
+ <script src="js/bootstrap.min.js"></script>
<!-- High Chart stuff -->
- <script src="http://code.highcharts.com/highcharts.js"></script>
- <script src="http://code.highcharts.com/modules/exporting.js"></script>
+ <script src="js/highcharts.js"></script>
+ <script src="js/highcharts-more.js"></script>
+ <script src="js/modules/exporting.js"></script>
</body>
</html>