From f5dcb764fae8bbbcbc33a4cf4f01e42c5606089d Mon Sep 17 00:00:00 2001 From: Michel Date: Thu, 17 Apr 2025 09:40:00 +0200 Subject: [PATCH] "Ajout de bouton pour PDF" --- domo91.py | 238 +++++++++++++++++++----------------------------------- 1 file changed, 85 insertions(+), 153 deletions(-) diff --git a/domo91.py b/domo91.py index 43c9972..fd21d46 100644 --- a/domo91.py +++ b/domo91.py @@ -5,7 +5,7 @@ import pandas as pd from datetime import date import matplotlib.pyplot as plt import matplotlib.dates as mdates -import random +from fpdf import FPDF st.set_page_config(page_title="Domo91 - Surveillance", layout="wide") st.title("📡 Supervision Températures") @@ -18,101 +18,16 @@ db_config = { "database": "Sondes" } -def afficher_tableau_filtré(df): - st.markdown("### 🔧 Filtrage horaire") - - df = df.copy() - df["Date"] = pd.to_datetime(df["Date"]) - - # Supprimer la colonne Id si elle existe - if "Id" in df.columns: - df.drop(columns="Id", inplace=True) - - # 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)"] - ) - - 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)] - - # Centrage de la colonne Température (et autres si souhaité) - def style_center(s): - return ['text-align: center'] * len(s) - - st.dataframe( - df.style.apply(style_center, subset=["Temperature"]), - use_container_width=True - ) - - return df - - +# --- 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"): @@ -140,8 +55,78 @@ 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") + def generer_pdf(site, date_str): + releves = { + "Chambre 1": [("06:00", 3.5), ("07:00", 3.2), ("08:00", 3.1)], + "Congélateur": [("06:00", -18.1), ("07:00", -17.8), ("08:00", -17.5)] + } + alertes = [ + {"Sonde": "Chambre 2", "Debut": f"{date_str} 08:45", "Statut": "En cours"}, + {"Sonde": "Congélateur", "Debut": f"{date_str} 12:30", "Statut": "Acquittée"} + ] + + 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) + + 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) + + 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']} - {a['Statut']}", 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 =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" + ) + + 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) @@ -151,7 +136,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"),) @@ -163,12 +151,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)) @@ -180,71 +171,12 @@ 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([5, 2, 5]) - 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}")