Initial commit projet IoT Flask ESP32

This commit is contained in:
Safouane Bazzi
2026-03-23 17:04:58 +01:00
parent 17026018a9
commit 06597bd9d3
7 changed files with 397 additions and 112 deletions

134
app.py
View File

@@ -1,12 +1,22 @@
from flask import Flask, jsonify, render_template, request, redirect, url_for, session
from flask_cors import CORS
from config import Config
from werkzeug.security import check_password_hash
from functools import wraps
from datetime import timedelta
import psycopg2
app = Flask(__name__)
app.config.from_object(Config)
app.secret_key = app.config["SECRET_KEY"]
app.config["SESSION_PERMANENT"] = True
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(hours=2)
app.config["SESSION_COOKIE_HTTPONLY"] = True
app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
app.config["SESSION_COOKIE_SECURE"] = False
CORS(app)
@@ -26,19 +36,24 @@ def get_setting_value(cur, key, default_value):
return row[0] if row else default_value
# ========================================================
# MODIFICATION ÉTUDIANT 3 : Sécurisation de l'accueil
# ========================================================
def admin_required(view_func):
@wraps(view_func)
def wrapped_view(*args, **kwargs):
if not session.get("admin_logged_in"):
return redirect(url_for("admin_login"))
return view_func(*args, **kwargs)
return wrapped_view
@app.before_request
def make_session_permanent():
session.permanent = True
@app.route("/")
@admin_required
def home():
# Si l'utilisateur n'est pas connecté en tant qu'admin,
# on le force à aller sur la page de connexion.
if not session.get("admin_logged_in"):
return redirect(url_for("admin_login"))
# S'il est connecté, on lui affiche le Dashboard.
return render_template("index.html")
# ========================================================
@app.route("/api/status")
@@ -52,32 +67,23 @@ def status():
@app.route("/api/data", methods=["POST"])
def receive_data():
data = request.get_json()
data = request.get_json(silent=True)
if not data:
return jsonify({"error": "Aucune donnée JSON reçue"}), 400
# Données environnement
temperature_ext = data.get("temperature_ext")
humidity_ext = data.get("humidity_ext")
system_status_msg = data.get("system_status")
# Données panneau solaire
voltage_pv = data.get("voltage_pv")
current_pv = data.get("current_pv")
# compatible solar_power
power_pv = data.get("power_pv", data.get("solar_power"))
luminosity = data.get("luminosity")
# Données batterie
voltage_battery = data.get("voltage_battery", data.get("battery_voltage"))
current_battery = data.get("current_battery")
# compatible battery_temperature
battery_temp = data.get("battery_temp", data.get("battery_temperature"))
battery_level = data.get("battery_level")
conn = get_connection()
@@ -91,10 +97,8 @@ def receive_data():
if battery_temp is not None and float(battery_temp) > max_battery_temperature:
battery_alert = "Température batterie trop élevée"
elif voltage_battery is not None and float(voltage_battery) < min_battery_voltage:
battery_alert = "Tension batterie trop faible"
elif power_pv is not None and float(power_pv) < min_solar_power:
battery_alert = "Puissance solaire insuffisante"
@@ -140,7 +144,6 @@ def receive_data():
@app.route("/api/latest", methods=["GET"])
def latest_data():
conn = get_connection()
cur = conn.cursor()
@@ -191,20 +194,69 @@ def latest_data():
})
@app.route("/api/history", methods=["GET"])
def history_data():
limit = request.args.get("limit", default=10, type=int)
if limit is None or limit <= 0:
limit = 10
if limit > 50:
limit = 50
conn = get_connection()
cur = conn.cursor()
cur.execute("""
SELECT
id,
created_at,
temperature_ext,
humidity_ext,
power_pv,
battery_level
FROM telemetry
ORDER BY created_at DESC
LIMIT %s
""", (limit,))
rows = cur.fetchall()
cur.close()
conn.close()
history = []
for row in reversed(rows):
history.append({
"id": row[0],
"created_at": str(row[1]),
"temperature_ext": row[2],
"humidity_ext": row[3],
"power_pv": row[4],
"battery_level": row[5]
})
return jsonify(history)
@app.route("/admin/login", methods=["GET", "POST"])
def admin_login():
if session.get("admin_logged_in"):
return redirect(url_for("home"))
if request.method == "POST":
username = request.form.get("username", "").strip()
password = request.form.get("password", "")
username = request.form.get("username")
password = request.form.get("password")
if not username or not password:
return render_template("login.html", error="Veuillez remplir tous les champs")
conn = get_connection()
cur = conn.cursor()
cur.execute(
"SELECT id FROM users WHERE username = %s AND password = %s AND is_admin = TRUE",
(username, password)
"SELECT id, username, password FROM users WHERE username = %s AND is_admin = TRUE",
(username,)
)
user = cur.fetchone()
@@ -213,13 +265,14 @@ def admin_login():
conn.close()
if user:
session["admin_logged_in"] = True
# ========================================================
# MODIFICATION ÉTUDIANT 3 : Redirection vers le Dashboard
# ========================================================
return redirect(url_for("home"))
# ========================================================
user_id, db_username, password_hash = user
if check_password_hash(password_hash, password):
session.clear()
session["admin_logged_in"] = True
session["admin_id"] = user_id
session["admin_username"] = db_username
return redirect(url_for("home"))
return render_template("login.html", error="Identifiants incorrects")
@@ -227,16 +280,12 @@ def admin_login():
@app.route("/admin/dashboard", methods=["GET", "POST"])
@admin_required
def admin_dashboard():
if not session.get("admin_logged_in"):
return redirect(url_for("admin_login"))
conn = get_connection()
cur = conn.cursor()
if request.method == "POST":
min_battery = request.form.get("min_battery")
max_temp = request.form.get("max_temp")
min_power = request.form.get("min_power")
@@ -276,11 +325,10 @@ def admin_dashboard():
return render_template("admin_dashboard.html", settings=settings)
@app.route("/admin/logout")
@app.route("/admin/logout", methods=["GET", "POST"])
@admin_required
def admin_logout():
session.pop("admin_logged_in", None)
session.clear()
return redirect(url_for("admin_login"))