aboutsummaryrefslogtreecommitdiffstats
path: root/sensor.py
diff options
context:
space:
mode:
authorMatt Kohls <mattkohls13@gmail.com>2021-04-23 23:42:42 -0400
committerMatt Kohls <mattkohls13@gmail.com>2021-04-23 23:42:42 -0400
commit437c1179b545927197637c26bb2d87d20401e5f2 (patch)
tree590e57b5dd6f0d707d8e95a7a5242bd1e892053f /sensor.py
parent352c56375b4ec2af8f0b593b450069271bcd65e2 (diff)
downloadSensor-Server-437c1179b545927197637c26bb2d87d20401e5f2.tar.gz
Sensor-Server-437c1179b545927197637c26bb2d87d20401e5f2.tar.bz2
Sensor-Server-437c1179b545927197637c26bb2d87d20401e5f2.zip
Update based on what is used nowHEADmaster
Many changes, mostly to make landing page more readable Oh and a file to read a sensor attached via i2c on a Raspberry Pi and add that to the db
Diffstat (limited to 'sensor.py')
-rwxr-xr-x[-rw-r--r--]sensor.py330
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')