Mercurial > ~darius > hgwebdir.cgi > iwws
changeset 13:a0213f0e707b
- Update for v12.10
- Plot raw data to show more up to date data
- Average/peak winds so they don't spam the display.
- Display the time of the most recent data.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Thu, 10 Jan 2013 16:38:36 +1030 |
parents | bfe6ed563ffc |
children | 294e6a7fbb6e |
files | iwws.py static/iwws.css static/iwws.js static/sprintf.js templates/index.html |
diffstat | 5 files changed, 221 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/iwws.py Wed Jun 20 12:57:30 2012 +0930 +++ b/iwws.py Thu Jan 10 16:38:36 2013 +1030 @@ -34,7 +34,7 @@ import calendar import datetime -import DataStore +import pywws.DataStore import flask import logging @@ -58,22 +58,39 @@ @app.route('/getdata.json') def getdata(): app.logger.debug("Getting data") - store = DataStore.hourly_store(DATA_DIR) + if 'duration' in flask.request.args: + duration = float(flask.request.args['duration']) + else: + duration = 24 * 60 * 60 + duration = datetime.timedelta(seconds = duration) + store = pywws.DataStore.data_store(DATA_DIR) now = datetime.datetime.now() - then = now - datetime.timedelta(1) + then = now - duration data = store[then:now] app.logger.debug("done") r = {} for k in store.key_list: r[k] = [] + # Raw data has absolute rain counts + baserain = None for d in data: + if baserain == None: + baserain = d['rain'] + delta = d['rain'] - baserain + # Sanity check + if d['rain'] < baserain or delta > 100: + delta = 0 + d['rain'] = delta + + lastdata = d['idx'] for k in d.keys(): if k == 'idx': t = int(dt2epoch(d[k])) r[k].append(t) else: r[k].append(d[k]) + r['lastdata'] = dt2epoch(lastdata) return flask.jsonify(r) def dt2epoch(dt):
--- a/static/iwws.css Wed Jun 20 12:57:30 2012 +0930 +++ b/static/iwws.css Thu Jan 10 16:38:36 2013 +1030 @@ -11,16 +11,23 @@ font-size: x-small; } + +div#stamp { + font-size: small; + margin-left : auto; + margin-right : auto; + height: 4%; +} div#graph1 { margin-left : auto; margin-right : auto; width: 97%; - height: 45%; + height: 43%; } div#graph2 { margin-left : auto; margin-right : auto; width: 97%; - height: 45%; + height: 43%; }
--- a/static/iwws.js Wed Jun 20 12:57:30 2012 +0930 +++ b/static/iwws.js Thu Jan 10 16:38:36 2013 +1030 @@ -45,28 +45,71 @@ var l = datacache['idx'].length - 1; var d = new Date(); var tzofs = d.getTimezoneOffset() * 60; + var wavgtmp = 0; + var wgusttmp = 0; + var winddir = 0; + var windavgs = 0; + var windnavg = 4; for (i = 0; i < l; i++) { - // Convert time from UTC to browser LT - t = datacache['idx'][i] - tzofs; + // Apply offset so Flot times look right (it always shows UTC) + t = (datacache['idx'][i] - tzofs) * 1000.0; + + // Keep track of min/max temperature if (datacache['temp_out'][i] < mint) mint = datacache['temp_out'] if (datacache['temp_out'][i] > maxt) maxt = datacache['temp_out'][i] - temp_out.push([t * 1000.0, datacache['temp_out'][i]]); - if (datacache['hum_out'][i] != null && datacache['temp_out'][i] != null) { - dewpt.push([t * 1000.0, hum2dp(datacache['hum_out'][i], datacache['temp_out'][i])]); + + // Store outside temperature if valid + if (datacache['temp_out'][i] != null) { + temp_out.push([t, datacache['temp_out'][i]]); + + // Calculate dewpoint if outside humidity is valid + if (datacache['hum_out'][i] != null) { + dewpt.push([t, hum2dp(datacache['hum_out'][i], datacache['temp_out'][i])]); + } } - wavg.push([t * 1000.0, datacache['wind_ave'][i] * 60.0 * 60.0 / 1000.0, wind2angle(datacache['wind_dir'][i])]); - wgust.push([t * 1000.0, datacache['wind_gust'][i] * 60.0 * 60.0 / 1000.0, wind2angle(datacache['wind_dir'][i])]); - pressure.push([t * 1000.0, datacache['abs_pressure'][i]]); + + // Store baro + pressure.push([t, datacache['abs_pressure'][i]]); + + // Store rain if there was any if (datacache['rain'][i] > 0) - rain.push([t * 1000.0, datacache['rain'][i]]); + rain.push([t, datacache['rain'][i]]); + + // Store wind (convert to km/r) + // Average the average wind speed + wavgtmp += datacache['wind_ave'][i] * 60.0 * 60.0 / 1000.0 + // Pick highest speed gusts + var g = datacache['wind_gust'][i] * 60.0 * 60.0 / 1000.0; + if (g > wgusttmp) { + wgusttmp = g; + } + // Accumulate speed/gust direction + winddir += wind2angle(datacache['wind_dir'][i]); + windavgs++; + // Normalise + if (windavgs == windnavg) { + windavgs = 0; + wavgtmp /= windnavg; + // Note: gust is peak, so nothing to do + winddir /= windnavg; + + // Store + wavg.push([t, wavgtmp, winddir]); + wgust.push([t, wgusttmp, winddir]); + + // Reset accumulators + wavgtmp = 0; + wgusttmp = 0; + winddir = 0; + } } $.plot($("#graph1"), [ - { data : pressure, label: "Baro", yaxis : 1, points : { show : true }, lines : { show : true } }, - { data : temp_out, label: "Temp.", yaxis : 2, points : { show : true }, lines : { show : true } }, - { data : dewpt, label: "Dew point", yaxis : 2, points : { show : true }, lines : { show : true } }, + { data : pressure, label: "Baro", yaxis : 1, points : { show : true, radius : 0 }, lines : { show : true } }, + { data : temp_out, label: "Temp.", yaxis : 2, points : { show : true, radius : 0 }, lines : { show : true } }, + { data : dewpt, label: "Dew point", yaxis : 2, points : { show : true, radius : 0 }, lines : { show : true } }, ], { xaxis : { mode : 'time' }, legend : { backgroundOpacity : 0, position : 'nw' }, @@ -75,7 +118,7 @@ }); $.plot($("#graph2"), [ { data : wavg, label: "Wind (Avg)", yaxis : 1, points : { show : true }, lines : { show : true }, direction : true }, - { data : wgust, label: "Wind (Gust)", yaxis : 1, points : { show : true }, lines : { show : true }, direction : true }, + { data : wgust, label: "Wind (Gust)", yaxis : 1, points : { show : true }, lines : { show : true }, direction : true }, { data : rain, label: "Rain", yaxis : 2, bars : { show : true, barWidth : 0.5 * 60 * 60 * 1000, align : "centre" } }, ], { xaxis : { mode : 'time' }, @@ -83,6 +126,10 @@ yaxis : { tickFormatter : spdFormatter }, y2axis : { min : 0, tickFormatter : mmFormatter } }); + // Reverse tzofs calculation as Date does local time + var dobj = new Date(datacache['lastdata'] * 1000.0); + $('#stamp').html(sprintf("Last data: %02d/%02d/%02d %02d:%02d:%02d", dobj.getFullYear(), dobj.getMonth() + 1, dobj.getDate(), + dobj.getHours(), dobj.getMinutes(), dobj.getSeconds())); } function wind2angle(dir) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/sprintf.js Thu Jan 10 16:38:36 2013 +1030 @@ -0,0 +1,130 @@ +/** + * + * Javascript sprintf + * http://www.webtoolkit.info/ + * + * + **/ + +sprintfWrapper = { + init : function () { + if (typeof arguments == "undefined") { return null; } + if (arguments.length < 1) { return null; } + if (typeof arguments[0] != "string") { return null; } + if (typeof RegExp == "undefined") { return null; } + + var string = arguments[0]; + var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g); + var matches = new Array(); + var strings = new Array(); + var convCount = 0; + var stringPosStart = 0; + var stringPosEnd = 0; + var matchPosEnd = 0; + var newString = ''; + var match = null; + + while (match = exp.exec(string)) { + if (match[9]) { convCount += 1; } + + stringPosStart = matchPosEnd; + stringPosEnd = exp.lastIndex - match[0].length; + strings[strings.length] = string.substring(stringPosStart, stringPosEnd); + + matchPosEnd = exp.lastIndex; + matches[matches.length] = { + match: match[0], + left: match[3] ? true : false, + sign: match[4] || '', + pad: match[5] || ' ', + min: match[6] || 0, + precision: match[8], + code: match[9] || '%', + negative: parseInt(arguments[convCount]) < 0 ? true : false, + argument: String(arguments[convCount]) + }; + } + strings[strings.length] = string.substring(matchPosEnd); + + if (matches.length == 0) { return string; } + if ((arguments.length - 1) < convCount) { return null; } + + var code = null; + var match = null; + var i = null; + + for (i=0; i<matches.length; i++) { + + if (matches[i].code == '%') { substitution = '%' } + else if (matches[i].code == 'b') { + matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2)); + substitution = sprintfWrapper.convert(matches[i], true); + } + else if (matches[i].code == 'c') { + matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument))))); + substitution = sprintfWrapper.convert(matches[i], true); + } + else if (matches[i].code == 'd') { + matches[i].argument = String(Math.abs(parseInt(matches[i].argument))); + substitution = sprintfWrapper.convert(matches[i]); + } + else if (matches[i].code == 'f') { + matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6)); + substitution = sprintfWrapper.convert(matches[i]); + } + else if (matches[i].code == 'o') { + matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8)); + substitution = sprintfWrapper.convert(matches[i]); + } + else if (matches[i].code == 's') { + matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length) + substitution = sprintfWrapper.convert(matches[i], true); + } + else if (matches[i].code == 'x') { + matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16)); + substitution = sprintfWrapper.convert(matches[i]); + } + else if (matches[i].code == 'X') { + matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16)); + substitution = sprintfWrapper.convert(matches[i]).toUpperCase(); + } + else { + substitution = matches[i].match; + } + + newString += strings[i]; + newString += substitution; + + } + newString += strings[i]; + + return newString; + + }, + + convert : function(match, nosign){ + if (nosign) { + match.sign = ''; + } else { + match.sign = match.negative ? '-' : match.sign; + } + var l = match.min - match.argument.length + 1 - match.sign.length; + var pad = new Array(l < 0 ? 0 : l).join(match.pad); + if (!match.left) { + if (match.pad == "0" || nosign) { + return match.sign + pad + match.argument; + } else { + return pad + match.sign + match.argument; + } + } else { + if (match.pad == "0" || nosign) { + return match.sign + match.argument + pad.replace(/0/g, ' '); + } else { + return match.sign + match.argument + pad; + } + } + } +} + +sprintf = sprintfWrapper.init; +
--- a/templates/index.html Wed Jun 20 12:57:30 2012 +0930 +++ b/templates/index.html Thu Jan 10 16:38:36 2013 +1030 @@ -12,6 +12,7 @@ <script type="text/javascript" src="static/jquery.log.js"></script> <script type="text/javascript" src="static/jquery.flot.js"></script> <script type="text/javascript" src="static/jquery.flot.direction.js"></script> + <script type="text/javascript" src="static/sprintf.js"></script> <script src="static/iwws.js" type="application/x-javascript" charset="utf-8"></script> </head> <body> @@ -22,6 +23,7 @@ <a href="#home" onclick="update_data()" class="button leftButton slideleft submit">Update</a> </div> <div id="container"> + <div id="stamp"> </div> <div id="graph1"></div> <div id="graph2"></div> </div>