164 lines
5.7 KiB
Python
164 lines
5.7 KiB
Python
import streamlit as st
|
|
import pandas as pd
|
|
import altair as alt
|
|
from dotenv import load_dotenv
|
|
from .utils_db import connect_to_mysql
|
|
|
|
st.set_page_config(page_title="Tech Chaufferie", layout="wide")
|
|
load_dotenv() # charger .env à la racine du projet
|
|
|
|
|
|
def login_commun():
|
|
login = st.text_input("Identifiant", type="default")
|
|
password = st.text_input("Mot de passe", type="password")
|
|
|
|
if st.button("Se connecter"):
|
|
user = verifier_utilisateur_commun(login, password)
|
|
if user:
|
|
st.session_state["authenticated"] = True
|
|
st.session_state["utilisateur"] = user["NomUtilisateur"]
|
|
st.success("✅ Connexion réussie")
|
|
st.rerun()
|
|
else:
|
|
st.error("❌ Identifiants incorrects ou expirés")
|
|
|
|
# Authentification
|
|
if "authenticated" not in st.session_state:
|
|
st.session_state["authenticated"] = False
|
|
|
|
if not st.session_state["authenticated"]:
|
|
st.title("🔧 Suivi des sondes de la chaufferie")
|
|
st.subheader("🔐 Connexion technicien chaufferie")
|
|
login_commun()
|
|
st.stop()
|
|
with st.sidebar:
|
|
st.markdown(f"👤 Connecté en tant que **{st.session_state['utilisateur']}**")
|
|
if st.button("🔓 Se déconnecter"):
|
|
st.session_state.clear()
|
|
st.rerun()
|
|
# --- Affichage principal ---
|
|
st.title("🔧 Suivi des sondes de la chaufferie")
|
|
|
|
data = get_latest_chaufferie()
|
|
df = pd.DataFrame(data)
|
|
|
|
# Ajout d'un statut couleur
|
|
def statut(temp):
|
|
if temp > 75:
|
|
return "❌ Très chaud"
|
|
elif temp > 60:
|
|
return "⚠️ Surveiller"
|
|
else:
|
|
return "✅ OK"
|
|
|
|
df["Statut"] = df["Temperature"].apply(statut)
|
|
|
|
# Séparer par topic
|
|
for topic in df["Topic"].unique():
|
|
st.subheader(f"Zone : {topic}")
|
|
st.dataframe(df[df["Topic"] == topic][["Sonde", "Temperature", "Date", "Statut"]], use_container_width=True)
|
|
|
|
# Graphique historique
|
|
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")
|
|
|
|
# ✅ 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):
|
|
conn = None
|
|
cursor = None
|
|
try:
|
|
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.")
|
|
|