diff --git a/domo91.py b/domo91.py index 0f7b645..26f5fe7 100644 --- a/domo91.py +++ b/domo91.py @@ -5,6 +5,8 @@ import pandas as pd from datetime import date import matplotlib.pyplot as plt import matplotlib.dates as mdates +from fpdf import FPDF +import os st.set_page_config(page_title="Domo91 - Surveillance", layout="wide") st.title("📡 Supervision Températures") @@ -17,101 +19,92 @@ db_config = { "database": "Sondes" } -def afficher_tableau_filtré(df): - st.markdown("### 🔧 Filtrage horaire") +# --- Fonction de génération PDF --- +def generer_pdf(site, date_str): + st.info(f"Génération du rapport PDF pour {site} à la date {date_str}") + try: + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor(dictionary=True) - df = df.copy() - df["Date"] = pd.to_datetime(df["Date"]) + cursor.execute(f"SELECT Sonde, Date, Temperature FROM `{site}` WHERE DATE(Date) = %s ORDER BY Sonde, Date", (date_str,)) + rows = cursor.fetchall() + df = pd.DataFrame(rows) + df["Heure"] = pd.to_datetime(df["Date"]).dt.strftime("%H:%M") - # Supprimer la colonne Id si elle existe - if "Id" in df.columns: - df.drop(columns="Id", inplace=True) + releves = {} + for sonde in df["Sonde"].unique(): + df_sonde = df[df["Sonde"] == sonde] + releves[sonde] = list(zip(df_sonde["Heure"], df_sonde["Temperature"])) - # Sélection de la tranche horaire - plage = st.selectbox( - "Sélectionnez une plage horaire :", - ["Toutes", "Matin (06h-12h)", "Après-midi (12h-18h)", "Soir (18h-00h)"] - ) + table_alertes = f"Alertes_{site}" + cursor.execute(f"SELECT Sonde, Debut_defaut, Status FROM {table_alertes} WHERE DATE(Debut_defaut) = %s", (date_str,)) + alertes = cursor.fetchall() - if plage == "Matin (06h-12h)": - df = df[(df["Date"].dt.hour >= 6) & (df["Date"].dt.hour < 12)] - elif plage == "Après-midi (12h-18h)": - df = df[(df["Date"].dt.hour >= 12) & (df["Date"].dt.hour < 18)] - elif plage == "Soir (18h-00h)": - df = df[(df["Date"].dt.hour >= 18)] + cursor.close() + conn.close() - # Centrage de la colonne Température (et autres si souhaité) - def style_center(s): - return ['text-align: center'] * len(s) + class RapportPDF(FPDF): + def header(self): + self.set_font("Arial", "B", 14) + self.cell(0, 10, "Rapport de surveillance des sondes", ln=1, align="C") + self.set_font("Arial", "", 12) + self.cell(0, 10, f"Date : {date_str}", ln=1, align="C") + self.ln(5) - st.dataframe( - df.style.apply(style_center, subset=["Temperature"]), - use_container_width=True - ) + def site_info(self, site_name): + self.set_font("Arial", "B", 12) + self.cell(0, 10, f"Site : {site_name}", ln=1) + self.ln(2) - return df + def releves_section(self, data): + self.set_font("Arial", "B", 12) + self.cell(0, 10, "Relevés de température", ln=1) + for sonde, mesures in data.items(): + self.set_font("Arial", "B", 11) + self.cell(0, 8, f"Sonde : {sonde}", ln=1) + self.set_font("Arial", "", 10) + for heure, temp in mesures: + self.cell(0, 6, f"{heure} - {temp} °C", ln=1) + self.ln(2) + def alertes_section(self, data): + self.set_font("Arial", "B", 12) + self.cell(0, 10, "Alertes enregistrées", ln=1) + self.set_font("Arial", "", 10) + for a in data: + self.cell(0, 6, f"{a['Sonde']} - {a['Debut_defaut']} - {a['Status']}", ln=1) + pdf = RapportPDF() + pdf.add_page() + pdf.site_info(site) + pdf.releves_section(releves) + pdf.alertes_section(alertes) + + file_name = f"rapport_{site}_{date_str}.pdf" + output_path = os.path.join("PDF", file_name) + pdf.output(output_path) + + with open(output_path, "rb") as f: + st.download_button( + label="📥 Télécharger le rapport PDF", + data=f, + file_name=file_name, + mime="application/pdf" + ) + + except Exception as e: + st.error(f"Erreur lors de la génération du PDF : {e}") + +# --- Initialisation session --- if "authenticated" not in st.session_state: st.session_state["authenticated"] = False st.session_state["role"] = None st.session_state["lieu_autorise"] = None -# --- Accès aux logs dès connexion superviseur --- -if st.session_state.get("authenticated") and st.session_state["role"] == "superviseur": - st.markdown("### 🔍 Accès à l’analyse des relevés") - if st.button("🧾 Analyse des logs Monitor.py"): - st.session_state["page"] = "analyse_logs" - st.rerun() - -# --- Analyse logs si page active --- -if st.session_state.get("page") == "analyse_logs": - st.title("🧾 Analyse des notifications de relevés") - try: - df_logs = pd.read_csv("/home/debian/travail/logs_monitor.csv", sep=";", parse_dates=["Date"]) - df_logs["Date_str"] = df_logs["Date"].dt.date - dates_dispo = sorted(df_logs["Date_str"].unique(), reverse=True) - date_selection = st.selectbox("📅 Sélectionnez une date :", dates_dispo) - lieux = sorted(df_logs["Lieu"].unique()) - lieu_selection = st.selectbox("📍 Site :", lieux) - df_filtré = df_logs[(df_logs["Date_str"] == date_selection) & (df_logs["Lieu"] == lieu_selection)] - sondes = sorted(df_filtré["Sonde"].unique()) - sonde_selection = st.selectbox("🧪 Sonde :", sondes) - df_sonde = df_filtré[df_filtré["Sonde"] == sonde_selection].copy() - - st.subheader(f"📈 Évolution de la température - {sonde_selection}") - fig, ax = plt.subplots(figsize=(10, 4)) - ax.plot(df_sonde["Date"], df_sonde["Température"], marker='o') - ax.set_title(f"{sonde_selection} - {date_selection}") - ax.set_xlabel("Heure") - ax.set_ylabel("Température (°C)") - ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) - st.pyplot(fig) - - st.subheader("📋 Détail des relevés") - - # Coloration conditionnelle des températures > seuil - df_sonde["Depassement"] = df_sonde["Température"] > df_sonde["Seuil"] - st.dataframe(df_sonde.style.apply( - lambda row: [ - 'background-color: red; color: white' if row["Depassement"] and col == "Température" else '' - for col in df_sonde.columns - ], axis=1 - ), use_container_width=True) - - st.markdown("---") - if st.button("⬅️ Retour à l'accueil"): - st.session_state["page"] = None - st.rerun() - - except Exception as e: - st.error(f"Erreur lecture logs : {e}") - st.stop() - - +# --- Sidebar (connexion + bouton PDF) --- with st.sidebar: st.header("🔐 Connexion") - if not st.session_state["authenticated"]: + if not st.session_state.get("authenticated"): login = st.text_input("Nom d'utilisateur") password = st.text_input("Mot de passe", type="password") if st.button("Se connecter"): @@ -139,8 +132,19 @@ with st.sidebar: st.session_state["lieu_autorise"] = None st.rerun() -# --- Interface principale + st.markdown("---") + st.subheader("📄 Rapport PDF") + if "selected_date" in st.session_state: + if st.button("📥 Télécharger l’état du jour (PDF)"): + site = st.session_state["lieu_autorise"] + date_val = st.session_state["selected_date"].strftime("%Y-%m-%d") + generer_pdf(site, date_val) + else: + st.info("Sélectionnez une date pour activer la génération PDF.") + +# --- CONTENU PRINCIPAL SI AUTHENTIFIÉ --- if st.session_state["authenticated"]: + st.markdown("## Sélection du site et de la date") try: conn = mysql.connector.connect(**db_config) cursor = conn.cursor(dictionary=True) @@ -150,7 +154,10 @@ if st.session_state["authenticated"]: else: site_selectionne = st.session_state["lieu_autorise"] st.info(f"Site imposé : {site_selectionne}") + selected_date = st.date_input("📅 Date du relevé", value=date.today()) + st.session_state["selected_date"] = selected_date + cursor.execute( f"SELECT * FROM `{site_selectionne}` WHERE DATE(Date) = %s ORDER BY Sonde, Date", (selected_date.strftime("%Y-%m-%d"),) @@ -162,12 +169,15 @@ if st.session_state["authenticated"]: sondes = sorted(df["Sonde"].unique()) sonde_choisie = st.selectbox("🧪 Choisissez une sonde :", sondes) df_sonde = df[df["Sonde"] == sonde_choisie] + cursor.execute("SELECT Temp_Max FROM Chambres_froides WHERE Lieu = %s AND Sonde = %s", (site_selectionne, sonde_choisie)) seuil = cursor.fetchone() seuil_temp = seuil["Temp_Max"] if seuil else 10 - df_filtré = afficher_tableau_filtré(df_sonde) - + st.subheader("📊 Tableau des relevés") + df_filtré = df_sonde.copy() + df_filtré = df_filtré.drop(columns="Id", errors="ignore") + st.dataframe(df_filtré, use_container_width=True) st.subheader("📈 Évolution de la température") fig, ax = plt.subplots(figsize=(10, 4)) @@ -179,71 +189,13 @@ if st.session_state["authenticated"]: ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) ax.legend() st.pyplot(fig) + else: st.warning("Aucune donnée trouvée pour cette date.") - # --- Alertes et bouton vers analyse logs --- - st.markdown("---") - st.subheader("🚨 Alertes de température") - if st.session_state["role"] == "superviseur": - if st.button("🧾 Voir les notifications relevées dans Monitor"): - st.session_state["page"] = "analyse_logs" - st.rerun() - - table_alertes = f"Alertes_{site_selectionne}" - voir_toutes = False - if st.session_state["role"] == "superviseur": - voir_toutes = st.toggle("Afficher toutes les alertes (y compris acquittées)", value=False) - if voir_toutes: - cursor.execute(f"SELECT * FROM {table_alertes} ORDER BY Debut_defaut DESC") - else: - cursor.execute(f"SELECT * FROM {table_alertes} WHERE Status = 'En cours' ORDER BY Debut_defaut DESC") - alertes = cursor.fetchall() - if alertes: - for alerte in alertes: - cols = st.columns([3, 3, 2, 2, 2]) - cols[0].markdown(f"**Sonde :** {alerte['Sonde']}") - cols[1].markdown(f"**Début :** {alerte['Debut_defaut'].strftime('%Y-%m-%d %H:%M')}") - cols[2].markdown(f"**Statut :** {alerte['Status']}") - if st.session_state["role"] == "superviseur" and alerte['Status'] == 'En cours': - key_btn = f"acq_{alerte['Id']}" - if cols[4].button("✅ Acquitter", key=key_btn): - cursor.execute(f"UPDATE {table_alertes} SET Status = 'Acquitté' WHERE Id = %s", (alerte['Id'],)) - conn.commit() - st.success(f"Alerte acquittée pour {alerte['Sonde']}") - st.rerun() - else: - st.info("✅ Aucune alerte en cours.") - - # --- Interface admin seuils / ON-OFF --- - if st.session_state["role"] == "superviseur": - st.markdown("---") - st.subheader("🛠️ Paramètres des sondes") - cursor.execute("SELECT * FROM Chambres_froides WHERE Lieu = %s", (site_selectionne,)) - sondes_info = cursor.fetchall() - if sondes_info: - for sonde in sondes_info: - cols = st.columns([3, 2, 3]) - cols[0].markdown(f"**{sonde['Sonde']}**") - etat_key = f"etat_{sonde['Id']}" - seuil_key = f"seuil_{sonde['Id']}" - etat_actuel = sonde["Etat"] == "ON" - new_etat = cols[1].checkbox("Actif", value=etat_actuel, key=etat_key) - new_seuil = cols[2].number_input("Seuil Max", min_value=-30.0, max_value=30.0, value=float(sonde["Temp_Max"]), step=0.5, key=seuil_key) - sonde["_new_etat"] = "ON" if new_etat else "OFF" - sonde["_new_seuil"] = new_seuil - if st.button("💾 Enregistrer les modifications"): - try: - for sonde in sondes_info: - cursor.execute("UPDATE Chambres_froides SET Etat = %s, Temp_Max = %s WHERE Id = %s", (sonde["_new_etat"], sonde["_new_seuil"], sonde["Id"])) - conn.commit() - st.success("✅ Modifications enregistrées.") - st.rerun() - except Exception as e: - st.error(f"Erreur lors de la mise à jour : {e}") - cursor.close() conn.close() except Exception as e: - st.error(f"Erreur MySQL : {e}") \ No newline at end of file + st.error(f"Erreur MySQL : {e}") +