Created
December 19, 2012 16:00
-
-
Save pingswept/4337794 to your computer and use it in GitHub Desktop.
Hacked first version of weather station code. Bloated, but works.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import sqlite3 | |
| import datetime | |
| sql_live = """SELECT | |
| strftime('%Y-%m-%d %H:%M GMT', logdate) AS logdate, | |
| avg({0}) AS {0} | |
| FROM log | |
| WHERE logdate >= datetime('now', '-180 minutes') | |
| GROUP BY strftime('%Y-%m-%d %H:%M', logdate) | |
| ORDER BY 1;""" | |
| sql_pastday = """SELECT | |
| strftime('%Y-%m-%d %H:%M GMT', min(logdate)) AS logdate, | |
| avg({0}) AS {0} | |
| FROM log | |
| WHERE logdate >= datetime('now', '-24 hours') | |
| GROUP BY strftime('%Y-%m-%d %H', logdate), strftime('%M', logdate) / 10 | |
| ORDER BY 1;""" | |
| sql_pastweek = """SELECT | |
| strftime('%Y-%m-%d %H:%M GMT', logdate) AS logdate, | |
| {0} | |
| FROM log_byhour | |
| WHERE logdate >= datetime('now', '-7 days') | |
| ORDER BY 1;""" | |
| sql_pastyear = """SELECT | |
| strftime('%Y-%m-%d 00:00:00 GMT', logdate) AS logdate, | |
| avg({0}) AS {0} | |
| FROM log_byhour | |
| GROUP BY strftime('%Y-%m-%d', logdate) | |
| HAVING logdate < date('now') | |
| ORDER BY 1;""" | |
| band_pastyear = """SELECT | |
| min({0}) AS min, | |
| max({0}) AS max | |
| FROM log_byhour | |
| GROUP BY strftime('%Y-%m-%d', logdate) | |
| HAVING logdate < date('now') | |
| ORDER BY logdate;""" | |
| sql_update = """INSERT INTO log_byhour | |
| (logdate, temperature, humidity, pressure) | |
| SELECT | |
| strftime('%Y-%m-%d %H:00:00', logdate) AS logdate, | |
| avg(temperature) AS temperature, | |
| avg(humidity) AS humidity, | |
| avg(pressure) AS pressure | |
| FROM log | |
| WHERE logdate >= ? AND logdate < ? | |
| GROUP BY strftime('%Y-%m-%d %H', logdate) | |
| ORDER BY 1;""" | |
| def log(temperature, humidity, pressure): | |
| logdate = datetime.datetime.utcnow() | |
| try: | |
| con = sqlite3.connect('/var/log/datalog.db') | |
| with con: | |
| cur = con.cursor() | |
| cur.execute('INSERT INTO log (logdate, temperature, humidity, pressure) VALUES(?, ?, ?, ?)', (logdate, temperature, humidity, pressure)) | |
| except Exception, e: | |
| print '## datalogger.log ## {0}'.format(e) | |
| def getlog(period): | |
| import json | |
| data = {} | |
| if period == 'pastyear': | |
| sql = sql_pastyear | |
| band = band_pastyear | |
| elif period == 'pastweek': | |
| sql = sql_pastweek | |
| band = '' | |
| elif period == 'pastday': | |
| sql = sql_pastday | |
| band = '' | |
| else: | |
| sql = sql_live | |
| band = '' | |
| con = sqlite3.connect('/var/log/datalog.db', detect_types=sqlite3.PARSE_DECLTYPES) | |
| with con: | |
| c = con.cursor() | |
| for val in ['temperature', 'humidity', 'pressure']: | |
| c.execute(sql.format(val)) | |
| data[val] = c.fetchall() | |
| if band != '': | |
| c.execute(band.format(val)) | |
| data[val + '_band'] = c.fetchall() | |
| return json.dumps(data) | |
| def update_byhour(): | |
| con = sqlite3.connect('/var/log/datalog.db', detect_types=sqlite3.PARSE_DECLTYPES) | |
| with con: | |
| c = con.cursor() | |
| # Get startDate for incremental update | |
| c.execute('SELECT MAX(logdate) FROM log_byhour;') | |
| startDate = c.fetchone()[0] | |
| if startDate == None: | |
| # Rascal24 arrival in UK | |
| startDate = datetime.datetime(2011, 12, 30) | |
| else: | |
| startDate = datetime.datetime.strptime(startDate, '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours = 1) | |
| # Get endDate | |
| c.execute("SELECT strftime('%Y-%m-%d %H:00:00','now');") | |
| endDate = c.fetchone()[0] | |
| # Update log_byhour | |
| for val in ['temperature', 'humidity', 'pressure']: | |
| c.execute(sql_update.format(val), (startDate, endDate)) | |
| rows = c.rowcount | |
| if rows > 0: | |
| c.execute("DELETE FROM log WHERE logdate < datetime('now', '-36 hours');") | |
| # print '## update_byhour ## deleted ' + str(c.rowcount) | |
| return rows | |
| def init(confirm): | |
| if confirm: | |
| logdate = datetime.datetime.utcnow() | |
| temperature = 21.2 | |
| humidity = 56 | |
| pressure = 29.375 | |
| con = sqlite3.connect('/var/log/datalog.db') | |
| with con: | |
| cur = con.cursor() | |
| cur.execute('DROP TABLE IF EXISTS log;') | |
| cur.execute('CREATE TABLE log(logdate TIMESTAMP, temperature REAL, humidity REAL, pressure REAL);') | |
| cur.execute('INSERT INTO log (logdate, temperature, humidity, pressure) VALUES(?, ?, ?, ?)', (logdate, temperature, humidity, pressure)) | |
| # Read back row to check, then delete | |
| con = sqlite3.connect('/var/log/datalog.db', detect_types=sqlite3.PARSE_DECLTYPES) | |
| con.row_factory = sqlite3.Row | |
| with con: | |
| c = con.cursor() | |
| c.execute('select * from log;') | |
| r = c.fetchone() | |
| print 'Logdate: ' + r['logdate'].strftime('%a, %d %b %Y %H:%M %Z') | |
| print 'Temperature: {0}'.format(r['temperature']) | |
| print 'Humidity: {0}'.format(r['humidity']) | |
| print 'Pressure: {0}'.format(r['pressure']) | |
| c.execute('delete from log;') | |
| else: | |
| print 'Set arg to True to initialise (deletes all data)' | |
| def init_byhour(confirm): | |
| if confirm: | |
| logdate = datetime.datetime.utcnow() | |
| temperature = 21.2 | |
| humidity = 56 | |
| pressure = 29.375 | |
| con = sqlite3.connect('/var/log/datalog.db') | |
| with con: | |
| cur = con.cursor() | |
| cur.execute('DROP TABLE IF EXISTS log_byhour;') | |
| cur.execute('CREATE TABLE log_byhour(logdate TIMESTAMP, temperature REAL, humidity REAL, pressure REAL);') | |
| cur.execute('INSERT INTO log_byhour (logdate, temperature, humidity, pressure) VALUES(?, ?, ?, ?)', (logdate, temperature, humidity, pressure)) | |
| # Read back row to check, then delete | |
| con = sqlite3.connect('/var/log/datalog.db', detect_types=sqlite3.PARSE_DECLTYPES) | |
| con.row_factory = sqlite3.Row | |
| with con: | |
| c = con.cursor() | |
| c.execute('select * from log_byhour;') | |
| r = c.fetchone() | |
| print 'Logdate: ' + r['logdate'].strftime('%a, %d %b %Y %H:%M %Z') | |
| print 'Temperature: {0}'.format(r['temperature']) | |
| print 'Humidity: {0}'.format(r['humidity']) | |
| print 'Pressure: {0}'.format(r['pressure']) | |
| c.execute('delete from log_byhour;') | |
| else: | |
| print 'Set arg to True to initialise (deletes all data)' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # datalogger stuff | |
| @rbtimer(30) | |
| def log_value(num): | |
| import datalogger | |
| # artemp = pytronics.i2cRead(0x48, 0, 'I', 2) | |
| # ftemp = ((artemp[0] << 4) | (artemp[1] >> 4)) * 0.0625 | |
| readings = pytronics.readWeatherBoard() | |
| # print '## temp_log ## ' + str(ftemp) | |
| temperature = (float(readings['temperature']) - 32.0) * 0.5555 | |
| humidity = readings['humidity'] | |
| pressure = readings['pressure'] | |
| datalogger.log(temperature, humidity, pressure) | |
| @cron(-30, -1, -1, -1, -1) | |
| def update_byhour(num): | |
| import datalogger | |
| rows = datalogger.update_byhour() | |
| if rows != 0: | |
| print '## updatelog ## added {0} row(s)'.format(rows) | |
| @public.route('/datalogger.html') | |
| def datalogger(): | |
| return render_template('datalogger.html', title='Temperature Log', label0='Temp {0}C'.format(unichr(176))) | |
| @public.route('/weather-station.html') | |
| def weather_station(): | |
| label0 = 'Temp {0}C'.format(unichr(176)) | |
| label1 = 'Humidity [%]' | |
| label2 = 'Pressure [in Hg]' | |
| return render_template('weather-station.html', title='Weather Log', label0=label0, label1=label1, label2=label2) | |
| @public.route('/getlog', methods=['POST']) | |
| def getlog(): | |
| import datalogger | |
| try: | |
| period = request.form['period'] | |
| except KeyError: | |
| period = 'live' | |
| return datalogger.getlog(period) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <title>Weather station demo</title> | |
| {% include "include/rascal-head.html" %} | |
| <script type="text/javascript" src="/static/js/jqplot-plugins/jqplot.dateAxisRenderer.js"></script> | |
| <script type="text/javascript" src="/static/js/jqplot-plugins/jqplot.highlighter.js"></script> | |
| <style> | |
| #temperature-chart, #humidity-chart, #pressure-chart { | |
| margin-top: 20px; | |
| height: 400px; | |
| width: 800px; | |
| } | |
| .jqplot-title, .jqplot-axis, .status { | |
| color: #ddd; | |
| } | |
| .jqplot-table-legend-label { | |
| color: #111; | |
| } | |
| .btn-group { | |
| margin-top: 10px; | |
| } | |
| img.led { | |
| opacity: 0.4; | |
| } | |
| img.led.active { | |
| opacity: 1; | |
| } | |
| .close { | |
| opacity: 0.6; | |
| } | |
| .close:hover { | |
| opacity: 1; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| {% include "include/rascal-topbar.html" %} | |
| <div class="container"> | |
| <div class="well rascal"> | |
| <h1>{{ title }}</h1> | |
| <div id="temperature-chart"></div> | |
| <div id="humidity-chart"></div> | |
| <div id="pressure-chart"></div> | |
| <div class="row-fluid"> | |
| <div class="span8"> | |
| <div class="btn-group" data-toggle="buttons-radio"> | |
| <button value="live" class="btn btn-default rascal active" style="width: 120px;">Live</button> | |
| <button value="pastday" class="btn btn-default rascal" style="width: 120px;">Past Day</button> | |
| <button value="pastweek" class="btn btn-default rascal" style="width: 120px;">Past Week</button> | |
| <button value="pastyear" class="btn btn-default rascal" style="width: 120px;">Past Year</button> | |
| </div> | |
| <img id="LED" src="static/images/led.gif" width="10" class="led" /> | |
| <small id="status" class="status"></small> | |
| </div> | |
| <div class="span4"> | |
| <div class="btn-group"> | |
| <button id="capture" value="capture" class="btn btn-default rascal" style="float: right;">Capture Image</button> | |
| </div> | |
| </div> | |
| </div> <!-- /row-fluid --> | |
| </div> <!-- /well --> | |
| <div id="captured-image" class="well rascal alert fade in" style="display:none;"> | |
| <!-- <button type="button" class="close"><img src="/editor/static/images/file-icons/delete.png"></button> --> | |
| <img class="close" src="/editor/static/images/file-icons/delete.png"> | |
| <p><small class="status">Right-click chart and choose Save Image As...</small></p> | |
| <div id="img-container"></div> | |
| </div> <!-- /well --> | |
| </div> <!-- /container --> | |
| <!-- {% include "include/doc-tab.html" %} --> | |
| <script type="text/javascript"> | |
| var temperatureChartOptions = { | |
| legend: { | |
| show: true, | |
| location: "ne" | |
| }, | |
| series: [ | |
| { label: "{{ label0 }}", lineWidth: 3, showMarker: false, rendererOptions: { smooth: true } } | |
| ], | |
| axes: { | |
| xaxis: { | |
| renderer: $.jqplot.DateAxisRenderer, | |
| tickOptions: {formatString: '%a%n%H:%M'} | |
| }, | |
| yaxis: { | |
| min: 13.0, | |
| max: 25.0 | |
| // tickOptions: {formatString: '%0.2f'} | |
| } | |
| }, | |
| highlighter: { | |
| show: true, | |
| sizeAdjust: 7.5 | |
| }, | |
| seriesColors: [ "#cd2820" ] | |
| }; | |
| var humidityChartOptions = { | |
| legend: { | |
| show: true, | |
| location: "ne" | |
| }, | |
| series: [ | |
| { label: "{{ label1 }}", lineWidth: 3, showMarker: false, rendererOptions: { smooth: true } } | |
| ], | |
| axes: { | |
| xaxis: { | |
| renderer: $.jqplot.DateAxisRenderer, | |
| tickOptions: {formatString: '%a%n%H:%M'} | |
| }, | |
| yaxis: { | |
| min: 0.0, | |
| max: 100.0 | |
| // tickOptions: {formatString: '%0.2f'} | |
| } | |
| }, | |
| highlighter: { | |
| show: true, | |
| sizeAdjust: 7.5 | |
| }, | |
| seriesColors: [ "#51a8cb" ] | |
| }; | |
| var pressureChartOptions = { | |
| legend: { | |
| show: true, | |
| location: "ne" | |
| }, | |
| series: [ | |
| { label: "{{ label2 }}", lineWidth: 3, showMarker: false, rendererOptions: { smooth: true } } | |
| ], | |
| axes: { | |
| xaxis: { | |
| renderer: $.jqplot.DateAxisRenderer, | |
| tickOptions: {formatString: '%a%n%H:%M'} | |
| }, | |
| yaxis: { | |
| min: 25.0, | |
| max: 32.0 | |
| // tickOptions: {formatString: '%0.2f'} | |
| } | |
| }, | |
| highlighter: { | |
| show: true, | |
| sizeAdjust: 7.5 | |
| }, | |
| seriesColors: [ "#414243" ] | |
| }; | |
| var | |
| period = 'live', | |
| interval = { live: 30*1000, pastday: 5*30*1000, pastweek: 30*60*1000, pastyear: 30*60*1000 }, | |
| tickFormat = { live: '%a%n%H:%M', pastday: '%a%n%H:%M', pastweek: '%a%n%H:%M', pastyear: '%e %b%n%Y' }, | |
| int_timer, | |
| capture_timeout, | |
| plot1, | |
| plot2, | |
| plot3; | |
| function updateGraph() { | |
| $('#LED').addClass('active'); | |
| $.post("/getlog", { period: period }, function (response) { | |
| var data = $.parseJSON(response), | |
| temperature = data.temperature, | |
| humidity = data.humidity, | |
| pressure = data.pressure, | |
| temperature_band = data.temperature_band, | |
| humidity_band = data.humidity_band, | |
| pressure_band = data.pressure_band; | |
| console.log(response); | |
| console.log('updateGraph last data ' + temperature[temperature.length - 1][0]); | |
| if (temperature_band !== undefined) { | |
| temperatureChartOptions.temperature[0].rendererOptions.bandData = temperature_band; | |
| } | |
| //} else { | |
| // delete temperatureChartOptions.temperature[0].rendererOptions.bandData; | |
| //} | |
| $('#temperature-chart').empty(); | |
| $('#humidity-chart').empty(); | |
| $('#pressure-chart').empty(); | |
| plot1 = $.jqplot('temperature-chart', [temperature], temperatureChartOptions); | |
| plot2 = $.jqplot('humidity-chart', [humidity], humidityChartOptions); | |
| plot3 = $.jqplot('pressure-chart', [pressure], pressureChartOptions); | |
| $('#status').text('Last update ' + new Date()); | |
| setTimeout(function () { | |
| $('#LED').removeClass('active'); | |
| }, 500); | |
| }).error(function (jqXHR, textStatus, errorThrown) { | |
| $('#status').text('Update failed (' + errorThrown + ') ' + new Date()); | |
| console.log('updateGraph: getlog: ' + textStatus + ': ' + errorThrown); | |
| }); | |
| } | |
| function captureImage() { | |
| var options = { | |
| x_offset: 0, | |
| y_offset: 0, | |
| backgroundColor: $('.well.rascal').css('background-color') | |
| }, | |
| imgElem = $('#temperature-chart').jqplotToImageElem(options); | |
| $('#img-container') | |
| .empty() | |
| .append(imgElem); | |
| $("#captured-image").fadeTo(250, 1); | |
| } | |
| // If update in progress, wait until finished (max 10s) | |
| function captureIfYouCan() { | |
| var isBusy = $('#LED').hasClass('active'); | |
| if (!isBusy) { | |
| captureImage(); | |
| } else { | |
| if (capture_timeout < 20) { | |
| capture_timeout += 1; | |
| console.log('Capture Image: waiting for update ' + capture_timeout); | |
| setTimeout(captureIfYouCan, 500); | |
| } else { | |
| console.log('Capture Image: timed out waiting for update'); | |
| } | |
| } | |
| } | |
| $('.btn').click(function () { | |
| var which = $(this).attr('value'); | |
| if (which === 'capture') { | |
| capture_timeout = 0; | |
| captureIfYouCan(); | |
| } else { | |
| int_timer = clearInterval(int_timer); | |
| period = which; | |
| console.log('Period set to ' + period + ' (refresh ' + (interval[period] / 1000).toString() + 's)'); | |
| temperatureChartOptions.axes.xaxis.tickOptions.formatString = tickFormat[period]; | |
| humidityChartOptions.axes.xaxis.tickOptions.formatString = tickFormat[period]; | |
| pressureChartOptions.axes.xaxis.tickOptions.formatString = tickFormat[period]; | |
| console.log(temperatureChartOptions.axes.xaxis.tickOptions.formatString); | |
| console.log(humidityChartOptions.axes.xaxis.tickOptions.formatString); | |
| console.log(pressureChartOptions.axes.xaxis.tickOptions.formatString); | |
| updateGraph(); | |
| int_timer = setInterval(updateGraph, interval[period]); | |
| } | |
| }); | |
| $(document).ready(function () { | |
| "use strict"; | |
| period = 'live' | |
| updateGraph(); | |
| int_timer = setInterval(updateGraph, interval[period]); | |
| $('.alert .close').live("click", function(e) { | |
| $(this).parent().fadeTo(350, 0, function () { | |
| $(this).hide(); | |
| }); | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment