From b35aa593d2c2ee44e5b1d10090442cd9dd80dee1 Mon Sep 17 00:00:00 2001 From: nils Date: Sun, 25 Feb 2024 10:51:37 +0100 Subject: [PATCH] Added flask web app --- .vscode/launch.json | 25 ++++++- docker-compose.yaml | 11 ++- web/.dockerignore | 26 +++++++ web/.gitignore | 107 +++++++++++++++++++++++++++++ web/Dockerfile | 27 ++++++++ web/requirements.txt | 3 + web/src/__init__.py | 10 +++ web/src/static/data.json | 5 ++ web/src/static/site.css | 32 +++++++++ web/src/templates/about.html | 7 ++ web/src/templates/contact.html | 7 ++ web/src/templates/hello_there.html | 16 +++++ web/src/templates/home.html | 7 ++ web/src/templates/layout.html | 25 +++++++ web/src/views.py | 48 +++++++++++++ web/src/webapp.py | 7 ++ web/update_reqs.sh | 1 + 17 files changed, 362 insertions(+), 2 deletions(-) create mode 100644 web/.dockerignore create mode 100644 web/.gitignore create mode 100644 web/Dockerfile create mode 100644 web/requirements.txt create mode 100644 web/src/__init__.py create mode 100644 web/src/static/data.json create mode 100644 web/src/static/site.css create mode 100644 web/src/templates/about.html create mode 100644 web/src/templates/contact.html create mode 100644 web/src/templates/hello_there.html create mode 100644 web/src/templates/home.html create mode 100644 web/src/templates/layout.html create mode 100644 web/src/views.py create mode 100644 web/src/webapp.py create mode 100755 web/update_reqs.sh diff --git a/.vscode/launch.json b/.vscode/launch.json index 01b8caf..4659624 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,6 +11,29 @@ "program": "${workspaceFolder}/alert-scheduler/src/watchdog.py", "console": "integratedTerminal", "cwd": "${workspaceFolder}/alert-scheduler" - } + }, + { + "name": "Web (Flask)", + "type": "python", + "request": "launch", + "module": "flask", + "env": { + "FLASK_APP": "web.src.webapp" + }, + "args": [ + "run", + "--no-debugger", + "--no-reload" + ] + }, + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "env": { + "FLASK_ENV": "development" + } + } ] } \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 2136fdd..c242da6 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,12 +3,21 @@ version: '3.4' services: watchdog: - image: watchdog + image: alert-scheduler restart: always build: context: ./alert-scheduler dockerfile: ./Dockerfile + web: + image: web + restart: unless-stopped + ports: + - 5200:5200 + build: + context: ./web + dockerfile: ./Dockerfile + mongo: image: mongo restart: always diff --git a/web/.dockerignore b/web/.dockerignore new file mode 100644 index 0000000..21bf6d4 --- /dev/null +++ b/web/.dockerignore @@ -0,0 +1,26 @@ +**/__pycache__ +**/.venv +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +README.md diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..45e7bbe --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,107 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +.vscode/ +settings.json diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 0000000..ff58c13 --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,27 @@ +# For more information, please refer to https://aka.ms/vscode-docker-python +FROM python:3.11-slim-bullseye + +EXPOSE 5200 + +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE=1 + +# Turns off buffering for easier container logging +ENV PYTHONUNBUFFERED=1 + +#RUN apt-get update && apt-get install -y iputils-ping + +# Install pip requirements +COPY requirements.txt . +RUN python -m pip install -r requirements.txt + +WORKDIR /app +COPY . /app + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app +USER appuser + +# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug +CMD ["gunicorn", "--bind", "0.0.0.0:5200", "--timeout", "60", "--workers", "2", "src.webapp:app"] diff --git a/web/requirements.txt b/web/requirements.txt new file mode 100644 index 0000000..863bae6 --- /dev/null +++ b/web/requirements.txt @@ -0,0 +1,3 @@ +Flask==3.0.2 +gunicorn==21.2.0 +paho_mqtt==2.0.0 diff --git a/web/src/__init__.py b/web/src/__init__.py new file mode 100644 index 0000000..b7a7f0a --- /dev/null +++ b/web/src/__init__.py @@ -0,0 +1,10 @@ +from flask import Flask # Import the Flask class +app = Flask(__name__) # Create an instance of the class for our use + +import paho.mqtt.client as mqtt +print("Starting up...") + +client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) + +client.connect("192.168.178.36",1884,keepalive=60) +client.publish("web2mqtt/status","Web2Mqtt starting up...") \ No newline at end of file diff --git a/web/src/static/data.json b/web/src/static/data.json new file mode 100644 index 0000000..d8fdc16 --- /dev/null +++ b/web/src/static/data.json @@ -0,0 +1,5 @@ +{ + "01": { + "note" : "Data is very simple because we're demonstrating only the mechanism." + } +} \ No newline at end of file diff --git a/web/src/static/site.css b/web/src/static/site.css new file mode 100644 index 0000000..c14da26 --- /dev/null +++ b/web/src/static/site.css @@ -0,0 +1,32 @@ +.message { + font-weight: 600; + color: blue; +} + +.navbar { + background-color: lightslategray; + font-size: 1em; + font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; + color: white; + padding: 8px 5px 8px 5px; +} + +.navbar a { + text-decoration: none; + color: inherit; +} + +.navbar-brand { + font-size: 1.2em; + font-weight: 600; +} + +.navbar-item { + font-variant: small-caps; + margin-left: 30px; +} + +.body-content { + padding: 5px; + font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} \ No newline at end of file diff --git a/web/src/templates/about.html b/web/src/templates/about.html new file mode 100644 index 0000000..8611b64 --- /dev/null +++ b/web/src/templates/about.html @@ -0,0 +1,7 @@ +{% extends "layout.html" %} +{% block title %} +About us +{% endblock %} +{% block content %} +

About page for the Visual Studio Code Flask tutorial.

+{% endblock %} diff --git a/web/src/templates/contact.html b/web/src/templates/contact.html new file mode 100644 index 0000000..3321c94 --- /dev/null +++ b/web/src/templates/contact.html @@ -0,0 +1,7 @@ +{% extends "layout.html" %} +{% block title %} +Contact us +{% endblock %} +{% block content %} +

Contact page for the Visual Studio Code Flask tutorial.

+{% endblock %} diff --git a/web/src/templates/hello_there.html b/web/src/templates/hello_there.html new file mode 100644 index 0000000..de1ef49 --- /dev/null +++ b/web/src/templates/hello_there.html @@ -0,0 +1,16 @@ + + + + + + Hello, Flask + + + {%if name %} + Hello there, {{ name }}! It's {{ date.strftime("%A, %d %B, %Y at %X") }}. + {% else %} + What's your name? Provide it after /hello/ in the URL. + {% endif %} + + + diff --git a/web/src/templates/home.html b/web/src/templates/home.html new file mode 100644 index 0000000..95609fe --- /dev/null +++ b/web/src/templates/home.html @@ -0,0 +1,7 @@ +{% extends "layout.html" %} +{% block title %} +Home +{% endblock %} +{% block content %} +

Home page for the Visual Studio Code Flask tutorial.

+{% endblock %} diff --git a/web/src/templates/layout.html b/web/src/templates/layout.html new file mode 100644 index 0000000..fd83b92 --- /dev/null +++ b/web/src/templates/layout.html @@ -0,0 +1,25 @@ + + + + + {% block title %}{% endblock %} + + + + + + +
+ {% block content %} + {% endblock %} +
+
+

© 2018

+
+
+ + diff --git a/web/src/views.py b/web/src/views.py new file mode 100644 index 0000000..e475367 --- /dev/null +++ b/web/src/views.py @@ -0,0 +1,48 @@ +from datetime import datetime +from flask import Flask, render_template,request +from . import app, client + +@app.route("/") +def home(): + return render_template("home.html") + +@app.route("/about/") +def about(): + return render_template("about.html") + +@app.route("/contact/") +def contact(): + return render_template("contact.html") + +@app.route("/hello/") +@app.route("/hello/") +def hello_there(name = None): + return render_template( + "hello_there.html", + name=name, + date=datetime.now() + ) + +@app.route("/api/data") +def get_data(): + return app.send_static_file("data.json") + +CMD = "web2mqtt/command" + +@app.route("/cmnd") +def command(): + opts = "" + command = CMD + + if request.args.get('cmnd'): + command += "/" + request.args.get('cmnd') + if request.args.get('opts'): + opts = request.args.get('opts') + + if not client.is_connected(): + print("reconnection to mqtt server...") + client.connect("192.168.178.36",1884,keepalive=60) + client.publish(command,opts) + + content = f"Command: {command} triggered with opts: {opts}" + return content \ No newline at end of file diff --git a/web/src/webapp.py b/web/src/webapp.py new file mode 100644 index 0000000..4e12521 --- /dev/null +++ b/web/src/webapp.py @@ -0,0 +1,7 @@ +# Entry point for the application. +import gunicorn +from . import app # For application discovery by the 'flask' command. +from . import views # For import side-effects of setting up routes. + +# Time-saver: output a URL to the VS Code terminal so you can easily Ctrl+click to open a browser +# print('http://127.0.0.1:5000/hello/VSCode') diff --git a/web/update_reqs.sh b/web/update_reqs.sh new file mode 100755 index 0000000..3675f47 --- /dev/null +++ b/web/update_reqs.sh @@ -0,0 +1 @@ +pipreqs . --force \ No newline at end of file