diff --git a/.gitignore b/.gitignore index 56c1acd..c770f86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *__pycache__* .venv* -.env +.env* mongo_data/* diff --git a/base.Dockerfile b/base.Dockerfile index 43f727a..9534f70 100644 --- a/base.Dockerfile +++ b/base.Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.10 as pool_base_image +FROM python:3.10 AS pool_base_image WORKDIR /pool_data @@ -9,4 +9,3 @@ RUN apt-get update -y && apt-get upgrade -y && apt-get install -y libsasl2-dev p RUN pip install --upgrade pip RUN pip --default-timeout=1000 install -r requirements.txt - diff --git a/docker-compose.yml b/docker-compose.yml index eeb547c..892a27c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: context: . dockerfile: flask.Dockerfile volumes: - - ./src/flask:/pool_data_web/src/flask + - ./src/flask:/pool_data/src/flask ports: - "80:80" - "5000:5000" diff --git a/flask.Dockerfile b/flask.Dockerfile index bc06c42..38e7fb8 100644 --- a/flask.Dockerfile +++ b/flask.Dockerfile @@ -1,4 +1,4 @@ -FROM pool_base_image as flask +FROM pool_base_image AS flask COPY requirements.txt . diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a578942 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[tool.pyright] +venvPath = "." +venv = ".venv" diff --git a/requirements.txt b/requirements.txt index e95fd0e..aaf30fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ click Flask-WTF bootstrap-flask waitress +bokeh diff --git a/src/flask/chart_test.html b/src/flask/chart_test.html new file mode 100644 index 0000000..0ce9862 --- /dev/null +++ b/src/flask/chart_test.html @@ -0,0 +1,61 @@ + + + + + Bokeh Plot + + + + + +
+ + + + + \ No newline at end of file diff --git a/src/flask/chart_test.py b/src/flask/chart_test.py new file mode 100644 index 0000000..d30feaa --- /dev/null +++ b/src/flask/chart_test.py @@ -0,0 +1,17 @@ +from bokeh.models.layouts import HBox +from bokeh.plotting import column +from charts import PoolCharts +from bokeh.io import output_file, show +from bokeh.layouts import row + +output_file("static/data_plot.html") + +chart = PoolCharts.PoolCharts() + +ph = chart.line_chart("Pool PH", "ph", 50) + +total_chlorine = chart.line_chart("Pool Total Chlorine", "total_chlorine", 50) + +free_chlorine = chart.line_chart("Pool Free Chlorine", "free_chlorine", 50) + +show(column(ph, total_chlorine, free_chlorine)) diff --git a/src/flask/charts/PoolCharts.py b/src/flask/charts/PoolCharts.py new file mode 100644 index 0000000..a15cd86 --- /dev/null +++ b/src/flask/charts/PoolCharts.py @@ -0,0 +1,49 @@ +import sys + +from bokeh.models.widgets import DataCube +from bokeh.plotting import figure + +from mongo.get_conn import db_conn + +class PoolCharts(): + def __init__(self): + self.db = db_conn() + + + def line_chart(self, title, field, limit): + data = self.db.pool_db + data = data.find({}).sort("date", -1).limit(limit) + dates = [] + data_list = [] + date_count = {} + for record in data: + if field in record and record[field] != "None": + if record["date"] not in dates: + print("new date record") + dates.append(record["date"]) + data_list.append(float(record[field])) + print (dates) + print (data_list) + else: + if record["date"] in date_count: + date_count[record["date"]] += 1 + else: + date_count[record["date"]] = 2 + print(len(data_list)) + current_data = data_list[len(data_list) - 1] + data_list[len(data_list) - 1] = (float(record[field]) + current_data) / date_count[record["date"]] + + print(dates) + print(data_list) + + p = figure(x_range=dates, height=250, title=title, + toolbar_location=None, tools="") + + p.line(x=dates, y=data_list) + + p.xgrid.grid_line_color = None + if not data_list: + p.y_range.start = 0 + else: + p.y_range.start = round(min(data_list) - 1) + return p diff --git a/src/flask/charts/__init__.py b/src/flask/charts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/flask/mongo/query_db.py b/src/flask/mongo/query_db.py index c8aa476..17c1491 100644 --- a/src/flask/mongo/query_db.py +++ b/src/flask/mongo/query_db.py @@ -23,7 +23,7 @@ class pool_query: queried record """ query = { "test_user" : f"{test_user}", "date" : f"{date}"} - record = self.db.real_db.find_one(query) + record = self.db.pool_db.find_one(query) if record: self.existing_record = record return True diff --git a/src/flask/pool_data.py b/src/flask/pool_data.py index 8f31be3..3c9e2db 100644 --- a/src/flask/pool_data.py +++ b/src/flask/pool_data.py @@ -1,3 +1,4 @@ +from bokeh.core.enums import SpatialUnitsType import mongo.build_db as pool_database import mongo.query_db as pool_database_query @@ -5,8 +6,13 @@ from flask import Flask, render_template, request, jsonify, redirect, session from flask_wtf import FlaskForm, CSRFProtect from flask_bootstrap import Bootstrap5 from wtforms import StringField, SubmitField, DateField, IntegerField, PasswordField, DecimalField, RadioField, TextAreaField -from wtforms.validators import DataRequired, Length +from wtforms.validators import DataRequired, Length, Optional from waitress import serve +from bokeh.models.layouts import HBox +from bokeh.plotting import column +from charts import PoolCharts +from bokeh.io import output_file, show +from bokeh.layouts import row app = Flask(__name__) app.secret_key = 'testsecret' #this value will change @@ -14,6 +20,21 @@ app.secret_key = 'testsecret' #this value will change bootstrap = Bootstrap5(app) csrf = CSRFProtect(app) +# used to configure the bokeh plot for graphs +output_file("/pool_data/src/flask/static/data_plot.html") + +def create_graphs(): + chart = PoolCharts.PoolCharts() + ph = chart.line_chart("Pool PH", "ph", 30) + total_chlorine = chart.line_chart("Pool Total Chlorine", "total_chlorine", 30) + free_chlorine = chart.line_chart("Pool Free Chlorine", "free_chlorine", 30) + alkalinity = chart.line_chart("Alkalinity", "alkalinity", 30) + salt = chart.line_chart("Salt", "salt", 30) + temp = chart.line_chart("Temperature", "temp", 30) + hardness = chart.line_chart("Hardness", "hardness", 30) + stabiliser = chart.line_chart("Stabiliser", "stabiliser", 30) + show(row(column(ph, total_chlorine, free_chlorine, temp), column(salt, alkalinity, hardness, stabiliser))) + class userForm(FlaskForm): username = StringField("User Name?", validators=[DataRequired()]) @@ -21,20 +42,20 @@ class userForm(FlaskForm): submit = SubmitField("Letsa GO!") class dataForm(FlaskForm): - test_user = RadioField("Tester:", + test_user = RadioField("Tester:", choices=[("Isabella"), ("Heather"), ("Ariah")]) Date = DateField("Date:") - free_chlorine = IntegerField("Free Chlorine:") - total_chlorine = IntegerField("Total Chlorine:") - alkalinity = DecimalField("Alkalinity:") - PH = DecimalField("PH:") - hardness = IntegerField("Hardness") - stabiliser = IntegerField("CYA - Stabliser") - salt = IntegerField("Salt:") - temp = DecimalField("Water Temperature") - comment = TextAreaField("Any Comments?") + free_chlorine = IntegerField("Free Chlorine:", validators=[Optional()]) + total_chlorine = IntegerField("Total Chlorine:", validators=[Optional()]) + alkalinity = DecimalField("Alkalinity:", validators=[Optional()]) + PH = DecimalField("PH:", validators=[Optional()]) + hardness = IntegerField("Hardness", validators=[Optional()]) + stabiliser = IntegerField("CYA - Stabliser", validators=[Optional()]) + salt = IntegerField("Salt:", validators=[Optional()]) + temp = DecimalField("Water Temperature", validators=[Optional()]) + comment = TextAreaField("Any Comments?", validators=[Optional()]) submit = SubmitField("Write it, Write it REAAAAAAL GOOOD") - + @app.route("/", methods=["GET","POST"]) def index(): form = userForm() @@ -54,7 +75,7 @@ def index(): def updater(): if 'logged_in' not in session: return redirect("/") - + create_graphs() query_db = pool_database_query.pool_query() query = query_db.get_top(10, "ph") form = dataForm() @@ -81,15 +102,15 @@ def updater(): if database.existing_record[field] != new_record[field]: database.update_re_record(database.existing_record["_id"], field, new_record[field]) else: - database.create_re_record(new_record["ph"], new_record["total_chlorine"], new_record["free_chlorine"], + database.create_re_record(new_record["ph"], new_record["total_chlorine"], new_record["free_chlorine"], new_record["alkalinity"], new_record["date"], new_record["test_user"], - new_record["temp"], new_record["hardness"], new_record["stabiliser"], + new_record["temp"], new_record["hardness"], new_record["stabiliser"], new_record["salt"], new_record["comment"]) - return render_template("updater.html", list=query, form=form) + return render_template("updater.html", list=query, form=form, success=True, updater_name = new_record["test_user"]) else: - return render_template("updater.html", list=query, form=form) + return render_template("updater.html", list=query, form=form, sucess=False) @app.route("/update_db", methods=["POST"]) def pool_data_update(): @@ -102,9 +123,9 @@ def pool_data_update(): if database.existing_record[field] != new_record[field]: database.update_re_record(database.existing_record["_id"], field, new_record[field]) else: - database.create_re_record(new_record["ph"], new_record["total_chlorine"], new_record["free_chlorine"], + database.create_re_record(new_record["ph"], new_record["total_chlorine"], new_record["free_chlorine"], new_record["alkalinity"], new_record["date"], new_record["test_user"], - new_record["temp"], new_record["hardness"], new_record["stabiliser"], + new_record["temp"], new_record["hardness"], new_record["stabiliser"], new_record["salt"], new_record["comment"]) @@ -117,4 +138,3 @@ def user_detail(id): if __name__ == '__main__': #app.run(host='0.0.0.0') serve(app, host='0.0.0.0', port=5000, url_scheme='https') - diff --git a/src/flask/static/data_plot.html b/src/flask/static/data_plot.html new file mode 100644 index 0000000..d5d1fd7 --- /dev/null +++ b/src/flask/static/data_plot.html @@ -0,0 +1,61 @@ + + + + + Bokeh Plot + + + + + +
+ + + + + \ No newline at end of file diff --git a/src/flask/templates/base.html b/src/flask/templates/base.html index be59d47..f619e1c 100644 --- a/src/flask/templates/base.html +++ b/src/flask/templates/base.html @@ -1,30 +1,26 @@ - + - - - + + + - - {% block title %} - Let there Be Pool Data - {% endblock %} - + {% block title %} Let there Be Pool Data {% endblock %} - {{ bootstrap.load_css() }} + {{ bootstrap.load_css() }} - - - - -{% block content %} -{% endblock %} + {% block content %} {% endblock %} - - -{{ bootstrap.load_js() }} - + + {{ bootstrap.load_js() }} + diff --git a/src/flask/templates/updater.html b/src/flask/templates/updater.html index b9380ed..8c8c088 100644 --- a/src/flask/templates/updater.html +++ b/src/flask/templates/updater.html @@ -5,7 +5,6 @@ Data Input {% endblock %} {% block content %} - + +
+
+ +
- - + + + {% endblock %} diff --git a/start_env b/start_env index 4657523..24424ac 100755 --- a/start_env +++ b/start_env @@ -1,4 +1,4 @@ -# /bin/bash +ou /bin/bash source .venv/bin/activate source .env