Interrupteur chambre froide
This commit is contained in:
@@ -24,7 +24,6 @@ import time
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from dotenv import load_dotenv, find_dotenv
|
from dotenv import load_dotenv, find_dotenv
|
||||||
|
|
||||||
# ========= .env (une seule fois) =========
|
# ========= .env (une seule fois) =========
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import matplotlib.dates as mdates
|
|||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import mysql.connector
|
import mysql.connector
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
pd.set_option("future.no_silent_downcasting", True)
|
pd.set_option("future.no_silent_downcasting", True)
|
||||||
import streamlit as st
|
import streamlit as st
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
@@ -820,7 +820,7 @@ if st.session_state.get("authenticated"):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Navigation + Pages (CORRIGÉ : pour superviseur ET utilisateur)
|
# Navigation + Pages
|
||||||
# =========================================================
|
# =========================================================
|
||||||
if st.session_state.get("authenticated"):
|
if st.session_state.get("authenticated"):
|
||||||
|
|
||||||
@@ -972,6 +972,7 @@ if st.session_state.get("authenticated"):
|
|||||||
st.text(traceback.format_exc())
|
st.text(traceback.format_exc())
|
||||||
|
|
||||||
# ------------------ Statistiques ------------------
|
# ------------------ Statistiques ------------------
|
||||||
|
|
||||||
elif onglet_selectionne == "Statistiques":
|
elif onglet_selectionne == "Statistiques":
|
||||||
st.markdown("## 📈 Statistiques de température")
|
st.markdown("## 📈 Statistiques de température")
|
||||||
|
|
||||||
@@ -1000,14 +1001,48 @@ if st.session_state.get("authenticated"):
|
|||||||
sondes = sorted(df["Sonde"].unique())
|
sondes = sorted(df["Sonde"].unique())
|
||||||
sonde = st.selectbox("Choisir une sonde :", sondes, key="selectbox_stats")
|
sonde = st.selectbox("Choisir une sonde :", sondes, key="selectbox_stats")
|
||||||
df_sonde = df[df["Sonde"] == sonde]
|
df_sonde = df[df["Sonde"] == sonde]
|
||||||
|
# Récupérer Temp_Max pour cette sonde (si définie)
|
||||||
|
seuil = None
|
||||||
|
try:
|
||||||
|
with closing(get_connection()) as conn_thr, closing(conn_thr.cursor(dictionary=True)) as cur_thr:
|
||||||
|
cur_thr.execute(
|
||||||
|
"SELECT Temp_Max FROM Sondes.Chambres_froides WHERE Lieu = %s AND Sonde = %s",
|
||||||
|
(site, sonde),
|
||||||
|
)
|
||||||
|
row_thr = cur_thr.fetchone()
|
||||||
|
if row_thr:
|
||||||
|
seuil = float(row_thr["Temp_Max"])
|
||||||
|
except Exception as e:
|
||||||
|
st.warning(f"Impossible de récupérer le seuil pour {sonde} : {e}")
|
||||||
st.subheader("Évolution journalière")
|
st.subheader("Évolution journalière")
|
||||||
fig, ax = plt.subplots(figsize=(10, 4))
|
fig, ax = plt.subplots(figsize=(10, 4))
|
||||||
ax.plot(df_sonde["Date"], df_sonde["Temperature"], marker="o")
|
|
||||||
|
dates = df_sonde["Date"]
|
||||||
|
temp = df_sonde["Temperature"]
|
||||||
|
|
||||||
|
if seuil is None:
|
||||||
|
# Pas de seuil trouvé : tracé classique
|
||||||
|
ax.plot(dates, temp, marker="o")
|
||||||
|
else:
|
||||||
|
# On sépare les valeurs normales et excessives
|
||||||
|
temp_ok = temp.where(temp <= seuil, np.nan)
|
||||||
|
temp_high = temp.where(temp > seuil, np.nan)
|
||||||
|
|
||||||
|
# Courbe normale
|
||||||
|
ax.plot(dates, temp_ok, marker="o")
|
||||||
|
|
||||||
|
# Partie excessive en rouge
|
||||||
|
ax.plot(dates, temp_high, marker="o", color="red")
|
||||||
|
|
||||||
|
# Ligne horizontale du seuil (optionnel mais très parlant)
|
||||||
|
ax.axhline(seuil, linestyle="--", linewidth=1)
|
||||||
|
ax.text(dates.iloc[0], seuil, f" Seuil {seuil}°C", va="bottom")
|
||||||
|
|
||||||
ax.set_title(f"{sonde} - {date_val.strftime('%d/%m/%Y')}")
|
ax.set_title(f"{sonde} - {date_val.strftime('%d/%m/%Y')}")
|
||||||
ax.set_xlabel("Heure")
|
ax.set_xlabel("Heure")
|
||||||
ax.set_ylabel("Température (°C)")
|
ax.set_ylabel("Température (°C)")
|
||||||
ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
|
ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
|
||||||
|
|
||||||
st.pyplot(fig)
|
st.pyplot(fig)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1022,13 +1057,18 @@ if st.session_state.get("authenticated"):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with closing(get_connection()) as conn_admin, closing(
|
with closing(get_connection()) as conn_admin, closing(
|
||||||
conn_admin.cursor(dictionary=True)) as cursor_admin:
|
conn_admin.cursor(dictionary=True)
|
||||||
cursor_admin.execute("SELECT * FROM Sondes.Chambres_froides WHERE Lieu = %s", (site,))
|
) as cursor_admin:
|
||||||
|
cursor_admin.execute(
|
||||||
|
"SELECT * FROM Sondes.Chambres_froides WHERE Lieu = %s", (site,)
|
||||||
|
)
|
||||||
chambres = cursor_admin.fetchall()
|
chambres = cursor_admin.fetchall()
|
||||||
|
|
||||||
if not chambres:
|
if not chambres:
|
||||||
st.warning("Aucune chambre froide pour ce site.")
|
st.warning("Aucune chambre froide pour ce site.")
|
||||||
else:
|
else:
|
||||||
|
table_alertes = f"Alertes_{site}"
|
||||||
|
|
||||||
for chambre in chambres:
|
for chambre in chambres:
|
||||||
col1, col2, col3 = st.columns([3, 1, 2])
|
col1, col2, col3 = st.columns([3, 1, 2])
|
||||||
with col1:
|
with col1:
|
||||||
@@ -1057,14 +1097,35 @@ if st.session_state.get("authenticated"):
|
|||||||
if st.button("▲", key=f"plus_{chambre['Id']}"):
|
if st.button("▲", key=f"plus_{chambre['Id']}"):
|
||||||
temp_max += 1
|
temp_max += 1
|
||||||
|
|
||||||
|
# Si quelque chose a changé (état ou Temp_Max)
|
||||||
if new_etat != chambre["Etat"] or temp_max != chambre["Temp_Max"]:
|
if new_etat != chambre["Etat"] or temp_max != chambre["Temp_Max"]:
|
||||||
|
# 1) Mise à jour de la chambre froide
|
||||||
cursor_admin.execute(
|
cursor_admin.execute(
|
||||||
"UPDATE Sondes.Chambres_froides SET Etat = %s, Temp_Max = %s WHERE Id = %s",
|
"UPDATE Sondes.Chambres_froides "
|
||||||
|
"SET Etat = %s, Temp_Max = %s WHERE Id = %s",
|
||||||
(new_etat, temp_max, chambre["Id"]),
|
(new_etat, temp_max, chambre["Id"]),
|
||||||
)
|
)
|
||||||
conn_admin.commit()
|
conn_admin.commit()
|
||||||
st.success(f"{chambre['Sonde']} mise à jour")
|
st.success(f"{chambre['Sonde']} mise à jour")
|
||||||
|
|
||||||
|
# 2) Si on vient de passer la chambre à OFF → acquitter les alertes
|
||||||
|
if new_etat == "OFF":
|
||||||
|
try:
|
||||||
|
cursor_admin.execute(
|
||||||
|
f"UPDATE Sondes.`{table_alertes}` "
|
||||||
|
"SET Etat = 'Acquitté' "
|
||||||
|
"WHERE Sonde = %s AND Etat <> 'Acquitté'",
|
||||||
|
(chambre["Sonde"],),
|
||||||
|
)
|
||||||
|
conn_admin.commit()
|
||||||
|
st.info(
|
||||||
|
f"Toutes les alertes en cours pour {chambre['Sonde']} ont été acquittées."
|
||||||
|
)
|
||||||
|
except Exception as e_alert:
|
||||||
|
st.error(
|
||||||
|
f"Erreur lors de l'acquittement des alertes pour {chambre['Sonde']} : {e_alert}"
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
st.error(f"Erreur SQL (admin) : {e}")
|
st.error(f"Erreur SQL (admin) : {e}")
|
||||||
st.text(traceback.format_exc())
|
st.text(traceback.format_exc())
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
import mysql.connector
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
import os
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
|
|
||||||
def connect_to_mysql():
|
|
||||||
return mysql.connector.connect(
|
|
||||||
host=os.getenv("DB_HOST"),
|
|
||||||
user=os.getenv("DB_USER"),
|
|
||||||
password=os.getenv("DB_PASS"),
|
|
||||||
database=os.getenv("DB_NAME")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_latest_chaufferie():
|
|
||||||
conn = connect_to_mysql()
|
|
||||||
cursor = conn.cursor(dictionary=True)
|
|
||||||
query = """
|
|
||||||
SELECT Sonde, Temperature, Date, Topic
|
|
||||||
FROM Sondes.Chaufferie
|
|
||||||
WHERE Date >= NOW() - INTERVAL 5 MINUTE
|
|
||||||
ORDER BY Date DESC \
|
|
||||||
"""
|
|
||||||
cursor.execute(query)
|
|
||||||
result = cursor.fetchall()
|
|
||||||
cursor.close()
|
|
||||||
conn.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_history_by_sonde(sonde):
|
|
||||||
conn = connect_to_mysql()
|
|
||||||
cursor = conn.cursor(dictionary=True)
|
|
||||||
query = """
|
|
||||||
SELECT Sonde, Temperature, Date
|
|
||||||
FROM Sondes.Chaufferie
|
|
||||||
WHERE Sonde = %s
|
|
||||||
AND Date >= NOW() - INTERVAL 1 DAY \
|
|
||||||
|
|
||||||
"""
|
|
||||||
cursor.execute(query, (sonde,))
|
|
||||||
result = cursor.fetchall()
|
|
||||||
cursor.close()
|
|
||||||
conn.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def lire_alertes_sondes():
|
|
||||||
conn = connect_to_mysql()
|
|
||||||
cursor = conn.cursor(dictionary=True)
|
|
||||||
query = """
|
|
||||||
SELECT Id, Sonde, Debut_defaut, Etat
|
|
||||||
FROM Sondes.Alertes_Chaufferie
|
|
||||||
WHERE Etat != 'Acquitté'
|
|
||||||
ORDER BY Debut_defaut DESC \
|
|
||||||
"""
|
|
||||||
cursor.execute(query)
|
|
||||||
result = cursor.fetchall()
|
|
||||||
cursor.close()
|
|
||||||
conn.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def acquitter_alerte(id_alerte):
|
|
||||||
conn = connect_to_mysql()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
query = "UPDATE Sondes.Alertes_Chaufferie SET Etat = 'Acquitté' WHERE Id = %s"
|
|
||||||
cursor.execute(query, (id_alerte,))
|
|
||||||
conn.commit()
|
|
||||||
cursor.close()
|
|
||||||
conn.close()
|
|
||||||
Reference in New Issue
Block a user