database access for rooms and mqtt client + generator
This commit is contained in:
141
web.py
141
web.py
@@ -1,19 +1,33 @@
|
||||
from db_connect import DatabaseConnect
|
||||
|
||||
from flask import Flask, abort, session
|
||||
from flask import Flask, abort, request, flash, redirect, get_flashed_messages
|
||||
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
|
||||
from jinja2 import FileSystemLoader, Template
|
||||
import plotly.express as px
|
||||
from plotly.subplots import make_subplots
|
||||
import plotly.graph_objects as go
|
||||
|
||||
import logging
|
||||
from os import sep
|
||||
import datetime
|
||||
|
||||
from db_connect import DatabaseConnect
|
||||
import templating
|
||||
import user_handling
|
||||
import components
|
||||
|
||||
app = Flask(__name__)
|
||||
db = DatabaseConnect()
|
||||
with open("session_key.txt","rb") as f:
|
||||
app.secret_key = f.read().strip()
|
||||
|
||||
|
||||
login_manager = LoginManager()
|
||||
login_manager.init_app(app)
|
||||
login_manager.anonymous_user = components.AnonymousUser
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
user_data = DatabaseConnect().username_from_id(user_id)
|
||||
if user_data:
|
||||
return components.User(user_id, user_data[0])
|
||||
return None
|
||||
|
||||
|
||||
Flask.jinja_options["loader"] = FileSystemLoader("web")
|
||||
env = app.create_jinja_environment()
|
||||
@@ -21,69 +35,106 @@ env = app.create_jinja_environment()
|
||||
DISPLAYEDTYPES = 2
|
||||
TDLATE = datetime.timedelta(hours=8)
|
||||
|
||||
# before and after
|
||||
TYPEUNITS = [
|
||||
"°C",
|
||||
"%"
|
||||
]
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if request.method == "POST":
|
||||
username = request.form["username"]
|
||||
password = request.form["password"]
|
||||
|
||||
user_data = DatabaseConnect().user_by_username(username)
|
||||
if user_data:
|
||||
user_id, _, salt, key = user_data
|
||||
if user_handling.verify_password(salt, key, password.encode()):
|
||||
user = components.User(user_id, username)
|
||||
login_user(user)
|
||||
DatabaseConnect().emit_log(3, f"User {username} logged in successfully.")
|
||||
return redirect("/")
|
||||
DatabaseConnect().emit_log(2, f"Failed login attempt for user {username}.")
|
||||
flash("Invalid username or password.")
|
||||
|
||||
return templating.LoginPage(env, current_user, roominfo=gather_room_info()).render()
|
||||
|
||||
@app.route("/logout")
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect("/")
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
# no user handling yet so we get user of ID 1 (not logged in)
|
||||
active_user = 1
|
||||
#populate userinfo
|
||||
user_info = templating.UserInfo(id=active_user, name=db.username_from_id(active_user)[0])
|
||||
|
||||
rooms_info = gather_room_info()
|
||||
|
||||
out_html = templating.LandingPage(env, current_user,rooms_info)
|
||||
return out_html.render()
|
||||
|
||||
def gather_room_info():
|
||||
rooms_info = []
|
||||
for room in db.view_valid_rooms(active_user):
|
||||
for room in DatabaseConnect().view_valid_rooms(current_user.id):
|
||||
sensor_info = []
|
||||
sensors_avail = db.get_sensors_in_room_id(room[2])
|
||||
sensors_avail = DatabaseConnect().get_sensors_in_room_id(room[2])
|
||||
for i in range(DISPLAYEDTYPES):
|
||||
sensors_with_type = [x for x in sensors_avail if x[1] == i]
|
||||
# TODO: handle more than one sensor in one room
|
||||
if sensors_with_type:
|
||||
reading = db.get_sensorsinfo_by_sensorid(sensors_with_type[0][0])
|
||||
reading = DatabaseConnect().get_sensorsinfo_by_sensorid(sensors_with_type[0][0])
|
||||
if reading is None:
|
||||
sensor_info.append(templating.SensorInfo(2,None, None, ""))
|
||||
sensor_info.append(components.SensorInfo(2,None, None, ""))
|
||||
continue
|
||||
reading = templating.SensorInfo(1 if reading.timestamp + TDLATE < datetime.datetime.now() else 0,
|
||||
reading = components.SensorInfo(1 if reading.timestamp + TDLATE < datetime.datetime.now() else 0,
|
||||
reading.type,
|
||||
reading.timestamp,
|
||||
f"{reading.reading}{TYPEUNITS[i]}")
|
||||
f"{reading.reading:.2f}{DatabaseConnect().get_unit_for_type(i) or ''}")
|
||||
sensor_info.append(reading)
|
||||
else:
|
||||
sensor_info.append(templating.SensorInfo(2,None, None, ""))
|
||||
rooms_info.append(templating.RoomInfo(room[0], room[1], sensor_info))
|
||||
|
||||
out_html = templating.LandingPage(env, user_info,rooms_info)
|
||||
return out_html.render()
|
||||
sensor_info.append(components.SensorInfo(2,None, None, ""))
|
||||
rooms_info.append(components.RoomInfo(room[0], room[1], sensor_info))
|
||||
return rooms_info
|
||||
|
||||
|
||||
|
||||
@app.route('/room/<room_name>')
|
||||
def room_page(room_name=None):
|
||||
if not db.user_has_room_perms(1,room_name):
|
||||
if not DatabaseConnect().user_has_room_perms(current_user.id,room_name):
|
||||
abort(403)
|
||||
|
||||
sensor_list = db.get_sensors_in_room_shortname(room_name)
|
||||
fig = make_subplots(rows=1, cols=len(sensor_list))
|
||||
for idx, sensorID in enumerate(sensor_list):
|
||||
lst = [x for x in db.get_sensor_data(sensorID)]
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x = [x[0] for x in lst],
|
||||
y = [x[1] for x in lst],
|
||||
name=db.get_sensor_type(sensorID)),
|
||||
row = 1,
|
||||
col = idx + 1
|
||||
)
|
||||
fig.update_layout(title_text=f"Available Devices in room {room_name}:")
|
||||
roominfos = gather_room_info()
|
||||
current_room = next((x for x in roominfos if x.shortcode == room_name), None)
|
||||
|
||||
#TODO: if statement to failsafe room with no sensors
|
||||
sensor_list = DatabaseConnect().get_sensors_in_room_shortname(room_name)
|
||||
fig = make_subplots(rows=1, cols=len(sensor_list))
|
||||
lastest_readings = []
|
||||
for idx, (sensorID, sensor_type) in enumerate(sensor_list):
|
||||
lst = [x for x in DatabaseConnect().get_sensor_data(sensorID)]
|
||||
if lst:
|
||||
lastest_readings.append(components.SensorInfo(
|
||||
1 if lst[0][0] + TDLATE < datetime.datetime.now() else 0,
|
||||
sensor_type,
|
||||
lst[0][0],
|
||||
f"{lst[0][1]:.2f}{DatabaseConnect().get_unit_for_type(sensor_type) or ''}"
|
||||
))
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x = [x[0] for x in lst],
|
||||
y = [x[1] for x in lst],
|
||||
name=DatabaseConnect().get_sensor_type(sensorID)),
|
||||
row = 1,
|
||||
col = idx + 1
|
||||
)
|
||||
|
||||
fig.update_layout(title_text=f"Available Devices in room {room_name}:")
|
||||
|
||||
return templating.RoomPage(
|
||||
env,
|
||||
current_user,
|
||||
roominfos,
|
||||
current_room,
|
||||
lastest_readings,
|
||||
fig.to_html(full_html=False, include_plotlyjs='cdn')
|
||||
).render()
|
||||
|
||||
template_path = f'web{sep}room_template.html'
|
||||
px_jinja_data = {"fig":fig.to_html(full_html=False)}
|
||||
with open(template_path,'r') as template_file:
|
||||
j2_template = Template(template_file.read())
|
||||
return j2_template.render(px_jinja_data)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
||||
Reference in New Issue
Block a user