Ajout foctions dans l'app
This commit is contained in:
118
Technique.py
118
Technique.py
@@ -1,8 +1,25 @@
|
|||||||
import streamlit as st
|
import streamlit as st
|
||||||
import pandas as pd
|
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")
|
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():
|
def login_commun():
|
||||||
login = st.text_input("Identifiant", type="default")
|
login = st.text_input("Identifiant", type="default")
|
||||||
@@ -58,17 +75,108 @@ for topic in df["Topic"].unique():
|
|||||||
st.markdown("---")
|
st.markdown("---")
|
||||||
st.header("📈 Historique par sonde (24h)")
|
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())
|
sonde_selection = st.selectbox("Choisir une sonde à afficher", df["Sonde"].unique())
|
||||||
|
|
||||||
if sonde_selection:
|
if sonde_selection:
|
||||||
historique = get_history_by_sonde(sonde_selection)
|
historique = get_history_by_sonde(sonde_selection)
|
||||||
if historique:
|
if historique:
|
||||||
df_hist = pd.DataFrame(historique)
|
df_hist = pd.DataFrame(historique)
|
||||||
df_hist["Date"] = pd.to_datetime(df_hist["Date"])
|
df_hist["Date"] = pd.to_datetime(df_hist["Date"])
|
||||||
|
df_hist["Temperature"] = pd.to_numeric(df_hist["Temperature"], errors="coerce")
|
||||||
|
|
||||||
st.line_chart(
|
# ✅ Message si -127°C détecté
|
||||||
df_hist.set_index("Date")["Temperature"],
|
if (df_hist["Temperature"] <= -126).any():
|
||||||
use_container_width=True
|
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:
|
else:
|
||||||
st.info("Aucune donnée disponible pour cette sonde dans les dernières 24h.")
|
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.")
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ paho-mqtt~=2.1.0
|
|||||||
requests~=2.32.3
|
requests~=2.32.3
|
||||||
schedule~=1.2.2
|
schedule~=1.2.2
|
||||||
paramiko~=3.5.1
|
paramiko~=3.5.1
|
||||||
dotenv
|
dotenv~=0.9.9
|
||||||
fpdf
|
fpdf~=1.7.2
|
||||||
ovh
|
ovh~=1.2.0
|
||||||
bcrypt
|
bcrypt~=4.3.0
|
||||||
|
altair
|
||||||
|
python-dotenv~=1.1.0
|
||||||
|
altair~=5.5.0
|
||||||
36
utils/db.py
36
utils/db.py
@@ -4,6 +4,42 @@ from dotenv import load_dotenv
|
|||||||
|
|
||||||
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):
|
def verifier_utilisateur_commun(login, password):
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user