diff --git a/app/Monitor.py b/app/Monitor.py index 0b63310..16ff65b 100644 --- a/app/Monitor.py +++ b/app/Monitor.py @@ -106,7 +106,7 @@ def surveiller(): envoyer_sms(lieu, message) alertes_actives[nom_sonde] = maintenant - # Vérifier retour à la normale (Acquittement) + # Vérifier retour à la normale (Acquittement) cursor.execute(f""" SELECT Temperature FROM {table_temp} WHERE Sonde = %s diff --git a/app/domo91.py b/app/domo91.py index f43722f..517c21e 100644 --- a/app/domo91.py +++ b/app/domo91.py @@ -339,7 +339,7 @@ if st.session_state["authenticated"]: df_sonde = df_sonde[(df_sonde["Heure"] >= 18) | (df_sonde["Heure"] < 6)] seuil_temp = 10 - cursor.execute("SELECT Temp_Max FROM Chambres_froides WHERE Lieu = %s AND Sonde = %s", + cursor.execute("SELECT Temp_Max FROM Sondes.Chambres_froides WHERE Lieu = %s AND Sonde = %s", (site_actuel, sonde_choisie)) seuil = cursor.fetchone() if seuil: @@ -439,7 +439,7 @@ if st.session_state["authenticated"]: try: conn_admin = mysql.connector.connect(**db_config) cursor_admin = conn_admin.cursor(dictionary=True) - cursor_admin.execute("SELECT * FROM Chambres_froides WHERE Lieu = %s", (site,)) + cursor_admin.execute("SELECT * FROM Sondes.Chambres_froides WHERE Lieu = %s", (site,)) chambres = cursor_admin.fetchall() if not chambres: @@ -470,7 +470,7 @@ if st.session_state["authenticated"]: if new_etat != chambre["Etat"] or temp_max != chambre["Temp_Max"]: cursor_admin.execute( - "UPDATE 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"]) ) conn_admin.commit() @@ -488,13 +488,13 @@ if st.session_state["authenticated"]: try: conn = get_connection() cursor = conn.cursor(dictionary=True) - cursor.execute("SELECT Id, Sonde, En_entretien FROM Chambres_froides WHERE Lieu = %s", (site_actuel,)) + cursor.execute("SELECT Id, Sonde, En_entretien FROM Sondes.Chambres_froides WHERE Lieu = %s", (site_actuel,)) sondes = cursor.fetchall() for sonde in sondes: checked = st.checkbox(f"{sonde['Sonde']}", value=sonde['En_entretien']) if checked != sonde['En_entretien']: - cursor.execute("UPDATE Chambres_froides SET En_entretien = %s WHERE Id = %s", + cursor.execute("UPDATE Sondes.Chambres_froides SET En_entretien = %s WHERE Id = %s", (checked, sonde['Id'])) conn.commit() st.success(f"{sonde['Sonde']} {'mise' if checked else 'retirée'} en entretien.") diff --git a/app/tracker.py b/app/tracker.py index f8db109..1d04b51 100644 --- a/app/tracker.py +++ b/app/tracker.py @@ -11,7 +11,6 @@ import re import time import json import hmac -from hashlib import sha256 # (non utilisé directement mais laissé si besoin d'évolution) from typing import Optional from datetime import date @@ -26,7 +25,6 @@ from dotenv import load_dotenv # ========================== load_dotenv() # lit .env si présent -TABLE_DB = os.getenv("MYSQL_DB", "Sondes") TABLE_NAME = "tracker" COL_ID = "id" COL_ADDRESS = "address" @@ -36,6 +34,7 @@ COL_MES = "mise_en_service" # DATE COL_RESBITS = "res_bits" COL_DATE = "date" +# Configuration BDD (standardisée sur les variables d'env MYSQL_*) DB_CFG = dict( host=os.getenv("DB_HOST"), user=os.getenv("DB_USER"), @@ -45,7 +44,7 @@ DB_CFG = dict( ) # Regex d'une ROM code DS18B20 au format {0x28,0xFF,0xAA,0xBB,0xCC,0xDD,0xEE,0xCRC} -ROM_REGEX = re.compile(r"^\{(?:0x[0-9A-Fa-f]{2},){7}0x[0-9A-Fa-f]{2}\}$") +ROM_REGEX = re.compile(r"^{(?:0x[0-9A-Fa-f]{2},){7}0x[0-9A-Fa-f]{2}}$") # Mapping résolution DS18B20 (bits -> infos) RES_MAP = { @@ -85,11 +84,15 @@ def require_login() -> Optional[str]: if st.session_state.get("auth_ok") and st.session_state.get("auth_user"): return st.session_state.get("auth_user") - st.markdown("

🔒 Accès restreint

", unsafe_allow_html=True) - with st.form("login_form", clear_on_submit=False): - username = st.text_input("Utilisateur") - password = st.text_input("Mot de passe", type="password") - ok = st.form_submit_button("Se connecter") + st.markdown("

🔒 Tracker

", unsafe_allow_html=True) + + # Formulaire centré + _, col2, _ = st.columns([1, 2, 1]) + with col2: + with st.form("login_form", clear_on_submit=False): + username = st.text_input("Utilisateur") + password = st.text_input("Mot de passe", type="password") + ok = st.form_submit_button("Se connecter") if ok: if verify_credentials(username, password): st.session_state["auth_ok"] = True @@ -183,24 +186,17 @@ def rom_help() -> str: """Message d'aide sur le format des adresses ROM DS18B20.""" return ( "Format attendu : `{0x28,0xFF,0xAA,0xBB,0xCC,0xDD,0xEE,0x12}` " - "(8 octets en hex).\n" + "(8 octets en hex)." "Le premier octet (famille) est souvent 0x28 pour DS18B20." ) def is_valid_rom(address: str) -> bool: """Vérifie que l'adresse saisie correspond bien au format attendu.""" - import re - ROM_REGEX = re.compile(r"^\{(?:0x[0-9A-Fa-f]{2},){7}0x[0-9A-Fa-f]{2}\}$") return bool(ROM_REGEX.match(address.strip())) + def res_label(bits: int) -> str: """Retourne un label lisible pour la résolution DS18B20.""" - RES_MAP = { - 9: {"precision": 0.5, "tconv_ms": 94}, - 10: {"precision": 0.25, "tconv_ms": 188}, - 11: {"precision": 0.125, "tconv_ms": 375}, - 12: {"precision": 0.0625,"tconv_ms": 750}, - } info = RES_MAP.get(bits) if not info: return f"{bits} bits (inconnu)" @@ -231,16 +227,6 @@ _all = fetch_trackers() lieux = sorted([x for x in _all[COL_LIEU].dropna().unique()]) if not _all.empty else [] lieu_selected = st.sidebar.selectbox("Filtrer par lieu", options=["(Tous)"] + lieux, index=0) -# Boutons d'export -col_exp1, col_exp2 = st.sidebar.columns(2) -with col_exp1: - if st.button("Exporter CSV"): - st.session_state["export_csv"] = True -with col_exp2: - if st.button("Recharger"): - st.cache_data.clear() - st.rerun() - # Formulaire d'ajout st.sidebar.subheader("Ajouter une sonde") with st.sidebar.form("add_form", clear_on_submit=True): @@ -368,20 +354,10 @@ else: with col3: st.caption(f"À enregistrer : {len(to_update)} mise(s) à jour, {len(removed_ids)} suppression(s)") - # Export CSV si demandé - if st.session_state.get("export_csv"): - out = edited.drop(columns=["resolution"]).copy() - st.download_button( - label="Télécharger CSV", - data=out.to_csv(index=False).encode("utf-8"), - file_name="trackers_export.csv", - mime="text/csv", - ) - st.session_state["export_csv"] = False - # Pied de page st.divider() st.caption( - "Astuce : vous pouvez coller directement une adresse ROM depuis vos logs au format {0x..,0x..,0x..,0x..,0x..,0x..,0x..,0x..}.\n" + "Astuce : vous pouvez coller directement une adresse ROM depuis vos logs au format {0x..,0x..,0x..,0x..,0x..,0x..,0x..,0x..}." + "Si vos noms de colonnes diffèrent, ajustez les constantes en tête de fichier." ) diff --git a/app/utils_db.py b/app/utils_db.py index 94d422f..8f24e26 100644 --- a/app/utils_db.py +++ b/app/utils_db.py @@ -17,7 +17,7 @@ def get_latest_chaufferie(): cursor = conn.cursor(dictionary=True) query = """ SELECT Sonde, Temperature, Date, Topic - FROM Chaufferie + FROM Sondes.Chaufferie WHERE Date >= NOW() - INTERVAL 5 MINUTE ORDER BY Date DESC """ @@ -32,10 +32,10 @@ def get_history_by_sonde(sonde): cursor = conn.cursor(dictionary=True) query = """ SELECT Sonde, Temperature, Date - FROM Chaufferie + FROM Sondes.Chaufferie WHERE Sonde = %s AND Date >= NOW() - INTERVAL 1 DAY - ORDER BY Date ASC + """ cursor.execute(query, (sonde,)) result = cursor.fetchall() @@ -48,7 +48,7 @@ def lire_alertes_sondes(): cursor = conn.cursor(dictionary=True) query = """ SELECT Id, Sonde, Debut_defaut, Etat - FROM Alertes_Chaufferie + FROM Sondes.Alertes_Chaufferie WHERE Etat != 'Acquitté' ORDER BY Debut_defaut DESC """ @@ -61,7 +61,7 @@ def lire_alertes_sondes(): def acquitter_alerte(id_alerte): conn = connect_to_mysql() cursor = conn.cursor() - query = "UPDATE Alertes_Chaufferie SET Etat = 'Acquitté' WHERE Id = %s" + query = "UPDATE Sondes.Alertes_Chaufferie SET Etat = 'Acquitté' WHERE Id = %s" cursor.execute(query, (id_alerte,)) conn.commit() cursor.close()