From b3c70abb6a07609f7fe367bd4b39afc365f5f166 Mon Sep 17 00:00:00 2001 From: Michel Date: Sun, 1 Jun 2025 09:54:35 +0200 Subject: [PATCH] Ajout foctions dans l'app --- Technique.py | 118 +++++++++++++++++++++++++++++++++++++++++++++-- requirements.txt | 11 +++-- utils/db.py | 36 +++++++++++++++ 3 files changed, 156 insertions(+), 9 deletions(-) diff --git a/Technique.py b/Technique.py index 490fe3f..5331fe3 100644 --- a/Technique.py +++ b/Technique.py @@ -1,8 +1,25 @@ import streamlit as st import pandas as pd -from utils.db import get_latest_chaufferie, get_history_by_sonde, verifier_utilisateur_commun +import mysql.connector +from utils.db import ( + get_latest_chaufferie, + get_history_by_sonde, + verifier_utilisateur_commun, + lire_alertes_sondes, + acquitter_alerte +) +import altair as alt +from dotenv import load_dotenv +import os st.set_page_config(page_title="Tech Chaufferie", layout="wide") +load_dotenv() # charger .env à la racine du projet + +# Accès aux variables d'environnement +MYSQL_HOST = os.getenv("DB_HOST") +MYSQL_USER = os.getenv("DB_USER") +MYSQL_PASSWORD = os.getenv("DB_PASSWORD") +MYSQL_DATABASE = os.getenv("DB_NAME") def login_commun(): login = st.text_input("Identifiant", type="default") @@ -58,17 +75,108 @@ for topic in df["Topic"].unique(): st.markdown("---") st.header("📈 Historique par sonde (24h)") +# Ce bloc doit exister pour que sonde_selection soit défini sonde_selection = st.selectbox("Choisir une sonde à afficher", df["Sonde"].unique()) - if sonde_selection: historique = get_history_by_sonde(sonde_selection) if historique: df_hist = pd.DataFrame(historique) df_hist["Date"] = pd.to_datetime(df_hist["Date"]) + df_hist["Temperature"] = pd.to_numeric(df_hist["Temperature"], errors="coerce") - st.line_chart( - df_hist.set_index("Date")["Temperature"], - use_container_width=True + # ✅ Message si -127°C détecté + if (df_hist["Temperature"] <= -126).any(): + st.error("🚨 Sonde défaillante détectée (-127°C). Vérification urgente requise.") + + # ✅ Ligne limite (modifiable ici) + limite = 80 + ligne_limite = alt.Chart(pd.DataFrame({ + "y": [limite] + })).mark_rule(color="red").encode(y="y") + + # ✅ Points rouge si erreur (-127°C) + alerte_sonde = alt.Chart(df_hist[df_hist["Temperature"] <= -126]).mark_point( + shape="cross", color="red", size=100 + ).encode( + x="Date:T", + y="Temperature:Q", + tooltip=["Date:T", "Temperature:Q"] ) + +# Insérer une alerte dans Mysql en cas de sonde défectueuse + def inserer_alerte_defaut_sonde(sonde, date_defaut): + conn = None + cursor = None + try: + conn = mysql.connector.connect( + host=MYSQL_HOST, + user=MYSQL_USER, + password=MYSQL_PASSWORD, + database=MYSQL_DATABASE + ) + cursor = conn.cursor() + + # Vérifie s'il existe déjà une alerte en cours + query_check = """ + SELECT COUNT(*) FROM Alertes_Chaufferie + WHERE Sonde = %s AND Etat = 'En cours' + """ + cursor.execute(query_check, (sonde,)) + count = cursor.fetchone()[0] + + if count == 0: + # Date du premier -127°C détecté + date_defaut = df_hist[df_hist["Temperature"] <= -126]["Date"].min() + + query_insert = """ + INSERT INTO Alertes_Chaufferie (Sonde, Debut_defaut, Etat) + VALUES (%s, %s, 'En cours') + """ + cursor.execute(query_insert, (sonde, date_defaut)) + conn.commit() + + except Exception as e: + st.warning(f"⚠️ Erreur enregistrement alerte : {e}") + + finally: + if cursor: + cursor.close() + if conn and conn.is_connected(): + conn.close() + + # 🔁 Appel de la fonction si -127 détecté + if (df_hist["Temperature"] <= -126).any(): + inserer_alerte_defaut_sonde(sonde_selection, df_hist["Date"].min()) + # ✅ Graphique principal + chart = alt.Chart(df_hist).mark_line().encode( + x=alt.X("Date:T", title="Date"), + y=alt.Y("Temperature:Q", title="Température (°C)", scale=alt.Scale(domain=[-130, 100])), + tooltip=["Date:T", "Temperature:Q"] + ).properties( + width=900, + height=400, + title=f"Évolution sur 24h de {sonde_selection}" + ) + + st.altair_chart(chart + ligne_limite + alerte_sonde, use_container_width=True) else: st.info("Aucune donnée disponible pour cette sonde dans les dernières 24h.") +st.markdown("---") +st.header("🧯 Alertes sondes défaillantes") + +alertes = lire_alertes_sondes() + +if alertes: + for alerte in alertes: + col1, col2, col3, col4 = st.columns([3, 3, 2, 2]) + col1.markdown(f"**Sonde :** {alerte['Sonde']}") + col2.markdown(f"**Défaut depuis :** {alerte['Debut_defaut'].strftime('%Y-%m-%d %H:%M')}") + col3.markdown(f"**État :** :orange[{alerte['Etat']}]") + + if alerte['Etat'] != 'Acquitté': + if col4.button("✅ Acquitter", key=f"acquitter_{alerte['Id']}"): + acquitter_alerte(alerte['Id']) + st.rerun() +else: + st.success("Aucune alerte active.") + diff --git a/requirements.txt b/requirements.txt index 86c7db9..1284486 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,10 @@ paho-mqtt~=2.1.0 requests~=2.32.3 schedule~=1.2.2 paramiko~=3.5.1 -dotenv -fpdf -ovh -bcrypt +dotenv~=0.9.9 +fpdf~=1.7.2 +ovh~=1.2.0 +bcrypt~=4.3.0 +altair +python-dotenv~=1.1.0 +altair~=5.5.0 \ No newline at end of file diff --git a/utils/db.py b/utils/db.py index a1a7333..74cc875 100644 --- a/utils/db.py +++ b/utils/db.py @@ -4,6 +4,42 @@ from dotenv import load_dotenv load_dotenv() +def lire_alertes_sondes(): + conn = None + cursor = None + try: + conn = get_connection() + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT * FROM Alertes_Chaufferie ORDER BY Debut_defaut DESC") + return cursor.fetchall() + except Exception as e: + import streamlit as st + st.warning(f"Erreur lecture alertes : {e}") + return [] + finally: + if cursor: + cursor.close() + if conn and conn.is_connected(): + conn.close() + +def acquitter_alerte(id_alerte): + conn = None + cursor = None + try: + conn = get_connection() + cursor = conn.cursor() + cursor.execute("UPDATE Alertes_Chaufferie SET Etat = 'Acquitté' WHERE Id = %s", (id_alerte,)) + conn.commit() + except Exception as e: + import streamlit as st + st.warning(f"Erreur lors de l'acquittement : {e}") + finally: + if cursor: + cursor.close() + if conn and conn.is_connected(): + conn.close() + + def verifier_utilisateur_commun(login, password): conn = get_connection() cursor = conn.cursor(dictionary=True)