diff options
Diffstat (limited to 'sensor.py')
-rwxr-xr-x[-rw-r--r--] | sensor.py | 330 |
1 files changed, 297 insertions, 33 deletions
diff --git a/sensor.py b/sensor.py index b21d51f..56c9594 100644..100755 --- a/sensor.py +++ b/sensor.py @@ -1,12 +1,19 @@ +#!/usr/bin/env python3 + # imports import sqlite3 -from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash +from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash, json, Response from contextlib import closing -from datetime import datetime -import pygal +from datetime import datetime, timedelta +from dateutil import parser + + +from io import BytesIO +from matplotlib.figure import Figure +import matplotlib.dates as mdates # configuration -DATABASE = '/tmp/sensors.db' +DATABASE = 'sensors.db' DEBUG = True SECRET_KEY = 'development_key' @@ -19,14 +26,46 @@ app.config.from_object(__name__) # initialize database def init_db(): with closing(connect_db()) as db: - with app.open_resource('schema.sql', mode='r') as f: - db.cursor().executescript(f.read()) + #with app.open_resource('schema.sql', mode='r') as f: + # db.cursor().executescript(f.read()) db.commit() # connect to database def connect_db(): return sqlite3.connect(app.config['DATABASE']) +# pull data between two dates +# startdate is for some date farther in the past than enddate +def dates_between(startdate, enddate, table, deviceId): + if table is 'weather': + subset = g.db.execute('SELECT date, temperature, humidity, pressure FROM weather WHERE date BETWEEN ? AND ?', [startdate, enddate]) + else: + subset = g.db.execute('SELECT date, temperature, humidity, pressure, battery FROM house WHERE (date BETWEEN ? AND ?) AND deviceId = ?', [startdate, enddate, deviceId]) + return subset + +def getCurrent(requestArgs): + # the args should be formatted YYYYMMDDHHMMSS + start = requestArgs.get('start') + end = requestArgs.get('end') + table = requestArgs.get('type') + deviceId = request.args.get('deviceId') + + # Sets default dates of information to be fetched, starttime will default to one day behind endtime, which defaults to now + if end is None: + endtime = datetime.now() + else: + endtime = datetime.strptime(end, "%Y%m%d%H%M%S") + if start is None: + starttime = endtime - timedelta(days=1) + else: + starttime = datetime.strptime(start, "%Y%m%d%H%M%S") + if table is None: + table = 'house' + if deviceId is None: + deviceId = 1 + + return dates_between(starttime, endtime, table, deviceId) + # handle requests @app.before_request def before_request(): @@ -41,47 +80,238 @@ def teardown_request(exception): # viewing database @app.route('/') def show_entries(): - cur = g.db.execute('SELECT date, temperature, humidity, pressure FROM weather ORDER BY id desc') + enddate = datetime.now() + startdate = enddate - timedelta(days=1) + deviceId = 1 + cur = g.db.execute('SELECT date, temperature, humidity, pressure FROM house WHERE (date BETWEEN ? AND ?) AND deviceId = ? ORDER BY id desc ', [startdate, enddate, deviceId]) entries = [dict(date=row[0], temperature=row[1], humidity=row[2], pressure=row[3]) for row in cur.fetchall()] + temp = "{:.1f}".format(entries[0].get("temperature") * 1.8 + 32) + humid = "{:.1f}".format(entries[0].get("humidity")) + current = dict(temperature=temp, humidity=humid) + + return render_template('show_entries.html', log=entries, current=current, devId=1) - return render_template('show_entries.html', weather=entries) +@app.route('/bedroom') +def bedroom_entries(): + enddate = datetime.now() + startdate = enddate - timedelta(days=1) + deviceId = 1 + cur = g.db.execute('SELECT date, temperature, humidity, pressure FROM house WHERE (date BETWEEN ? AND ?) AND deviceId = ? ORDER BY id desc ', [startdate, enddate, deviceId]) + entries = [dict(date=row[0], temperature=row[1], humidity=row[2], pressure=row[3]) for row in cur.fetchall()] + temp = "{:.1f}".format(entries[0].get("temperature") * 1.8 + 32) + humid = "{:.1f}".format(entries[0].get("humidity")) + current = dict(temperature=temp, humidity=humid) + + return render_template('show_entries.html', log=entries, current=current, devId=1) + +@app.route('/mainfloor') +def mainfloor_entries(): + enddate = datetime.now() + startdate = enddate - timedelta(days=1) + deviceId = 2 + cur = g.db.execute('SELECT date, temperature, humidity, pressure FROM house WHERE (date BETWEEN ? AND ?) AND deviceId = ? ORDER BY id desc ', [startdate, enddate, deviceId]) + entries = [dict(date=row[0], temperature=row[1], humidity=row[2], pressure=row[3]) for row in cur.fetchall()] + temp = "{:.1f}".format(entries[0].get("temperature") * 1.8 + 32) + humid = "{:.1f}".format(entries[0].get("humidity")) + current = dict(temperature=temp, humidity=humid) + + return render_template('show_entries.html', log=entries, current=current, devId=2) + +@app.route('/interactive') +def interactive(): + return render_template('interactive.html') # drawing graphs -@app.route('/tgraph.svg') +@app.route('/tgraph.png', methods=['GET']) def draw_t_graph(): - cur = g.db.execute('SELECT date, temperature, humidity, pressure FROM weather ORDER BY id desc') + cur = getCurrent(request.args) + data = cur.fetchall() + dates = [] + tempsC = [] + tempsF = [] - datetimeline = pygal.DateTimeLine( - x_label_rotation=30, truncate_label=-1, - x_value_formatter=lambda dt: dt.strftime('%d, %b %Y %I:%M %p') - ) - datetimeline.add("Temp", [(datetime.strptime(row[0], '%Y-%m-%d %H:%M:%S.%f'), float(row[1])) for row in cur.fetchall()]) + for row in data: + dates.append(parser.parse(row[0])) + tempsC.append(row[1]) + tempsF.append(row[1] * 1.8 + 32) - return datetimeline.render_response() + # Generate the figure **without using pyplot**. + fig = Figure() + ax = fig.subplots() + bx = ax.twinx() + locator = mdates.AutoDateLocator(minticks=3, maxticks=7) + formatter = mdates.ConciseDateFormatter(locator) + ax.xaxis.set_major_locator(locator) + ax.xaxis.set_major_formatter(formatter) + bx.xaxis.set_major_locator(locator) + bx.xaxis.set_major_formatter(formatter) + ax.plot(dates, tempsC, color="C1") + ax.set_xlabel("Timestamps") + ax.set_ylabel("Celsius") + ax.set_title("Temperature") + bx.plot(dates, tempsF, visible=False) + bx.set_ylabel("Fahrenheit") + # Save it to a temporary buffer. + buf = BytesIO() + fig.savefig(buf, format="png") -@app.route('/hgraph.svg') + return Response(buf.getvalue(), mimetype='image/png') + +@app.route('/hgraph.png', methods=['GET']) def draw_h_graph(): - cur = g.db.execute('SELECT date, temperature, humidity, pressure FROM weather ORDER BY id desc') + data = getCurrent(request.args) + dates = [] + humidities = [] + + for row in data: + dates.append(parser.parse(row[0])) + humidities.append(row[2]) + + # Generate the figure **without using pyplot**. + fig = Figure() + ax = fig.subplots() + locator = mdates.AutoDateLocator(minticks=3, maxticks=7) + formatter = mdates.ConciseDateFormatter(locator) + ax.xaxis.set_major_locator(locator) + ax.xaxis.set_major_formatter(formatter) + ax.plot(dates, humidities, color="C0") + ax.set_xlabel("Timestamps") + ax.set_ylabel("Percent") + ax.set_title("Relative Humidity") + # Save it to a temporary buffer. + buf = BytesIO() + fig.savefig(buf, format="png") + + return Response(buf.getvalue(), mimetype='image/png') + +@app.route('/htgraph.png', methods=['GET']) +def draw_ht_graph(): + cur = getCurrent(request.args) + data = cur.fetchall() + dates = [] + humidities = [] + #tempsC = [] + tempsF = [] + + for row in data: + dates.append(parser.parse(row[0])) + # tempsC.append(row[1]) + tempsF.append(row[1] * 1.8 + 32) + humidities.append(row[2]) + + fig = Figure() + #fig.subplots_adjust(right=0.75) + ax = fig.subplots() + bx = ax.twinx() + #cx = ax.twinx() - datetimeline = pygal.DateTimeLine( - x_label_rotation=30, truncate_label=-1, - x_value_formatter=lambda dt: dt.strftime('%d, %b %Y %I:%M %p') - ) - datetimeline.add("Humidity", [(datetime.strptime(row[0], '%Y-%m-%d %H:%M:%S.%f'), float(row[2])) for row in cur.fetchall()]) + #cx.spines["right"].set_position(("axes", 1.2)) + #cx.set_frame_on(True) + #cx.patch.set_visible(False) + #for sp in cx.spines.values(): + # sp.set_visible(False) + #cx.spines["right"].set_visible(True) - return datetimeline.render_response() + locator = mdates.AutoDateLocator(minticks=3, maxticks=7) + formatter = mdates.ConciseDateFormatter(locator) + ax.xaxis.set_major_locator(locator) + ax.xaxis.set_major_formatter(formatter) + bx.xaxis.set_major_locator(locator) + bx.xaxis.set_major_formatter(formatter) + #cx.xaxis.set_major_locator(locator) + #cx.xaxis.set_major_formatter(formatter) -@app.route('/pgraph.svg') + hline, = ax.plot(dates, humidities, color="C0", label="Relative Humidity") + ax.set_xlabel("Timestamps") + ax.set_ylabel("Percent") + ax.set_title("Humidity and Temperature") + tline, = bx.plot(dates, tempsF, color="C1", label="Temperature") + bx.set_ylabel("Fahrenheit") + #cx.plot(dates, tempsC, visible=False) + #cx.set_ylabel("Celsius") + + lines = [hline, tline] + ax.legend(lines, [l.get_label() for l in lines]) + + buf = BytesIO() + fig.savefig(buf, format="png") + + return Response(buf.getvalue(), mimetype='image/png') + +@app.route('/pgraph.png', methods=['GET']) def draw_p_graph(): - cur = g.db.execute('SELECT date, temperature, humidity, pressure FROM weather ORDER BY id desc') + data = getCurrent(request.args) + dates = [] + pressures = [] + + for row in data: + dates.append(parser.parse(row[0])) + pressures.append(row[3]) + + # Generate the figure **without using pyplot**. + fig = Figure() + ax = fig.subplots() + locator = mdates.AutoDateLocator(minticks=3, maxticks=7) + formatter = mdates.ConciseDateFormatter(locator) + ax.xaxis.set_major_locator(locator) + ax.xaxis.set_major_formatter(formatter) + ax.plot(dates, pressures, color="C2") + ax.set_xlabel("Timestamps") + ax.set_ylabel("hPa") + ax.set_title("Pressure") + # Save it to a temporary buffer. + buf = BytesIO() + fig.savefig(buf, format="png") + + return Response(buf.getvalue(), mimetype='image/png') + +@app.route('/bgraph.png', methods=['GET']) +def draw_b_graph(): + data = getCurrent(request.args) + dates = [] + batteries = [] + + for row in data: + dates.append(parser.parse(row[0])) + batteries.append(row[4]) + + # Generate the figure **without using pyplot**. + fig = Figure() + ax = fig.subplots() + locator = mdates.AutoDateLocator(minticks=3, maxticks=7) + formatter = mdates.ConciseDateFormatter(locator) + ax.xaxis.set_major_locator(locator) + ax.xaxis.set_major_formatter(formatter) + ax.plot(dates, batteries, color="C3") + ax.set_xlabel("Timestamps") + ax.set_ylabel("Volts") + ax.set_title("Battery Voltage") + # Save it to a temporary buffer. + buf = BytesIO() + fig.savefig(buf, format="png") - datetimeline = pygal.DateTimeLine( - x_label_rotation=30, truncate_label=-1, - x_value_formatter=lambda dt: dt.strftime('%d, %b %Y %I:%M %p') - ) - datetimeline.add("Pressure", [(datetime.strptime(row[0], '%Y-%m-%d %H:%M:%S.%f'), float(row[3])) for row in cur.fetchall()]) + return Response(buf.getvalue(), mimetype='image/png') - return datetimeline.render_response() +## Database Retrieval Route +# +# Sends the information in the database in JSON format +@app.route('/get_database') +def get_database(): + entries = getCurrent(request.args) + empList = [] + for emp in entries: + empDict = { + 'date': emp[0], + 'temperature': emp[1], + 'humidity': emp[2], + 'pressure': emp[3] } + empList.append(empDict) + response = app.response_class( + response=json.dumps(empList), + status=200, + mimetype='application/json' + ) + return response # adding entries to database @@ -100,5 +330,39 @@ def add_data(): return render_template('show_entries.html'), 200 +@app.route('/json_data', methods=['POST']) +def add_json_data(): + mkey = request.args.get('key') + if mkey != SECRET_KEY: + abort(401) + + # Validate the request body contains JSON + if request.is_json: + # Parse the JSON into a Python dictionary + req = request.get_json() + + # Print the dictionary + print(req) + + try: + temp = req['temperature'] + humidity = req['humidity'] + pressure = req['pressure'] + battery = req['battery'] + deviceId = req['deviceId'] + now = datetime.now() + g.db.execute('INSERT INTO house (date, temperature, humidity, pressure, deviceId, battery) VALUES (?, ?, ?, ?, ?, ?)', [now, temp, humidity, pressure, deviceId, battery]) + g.db.commit() + except: + print("bad json") + + # Return a string along with an HTTP status code + return "JSON received!", 200 + + else: + # The request body wasn't JSON so return a 400 HTTP status code + return "Request was not JSON", 400 + + if __name__ == '__main__': - app.run() + app.run(host='0.0.0.0') |