Mise au point des monitoring

This commit is contained in:
2025-09-20 16:27:02 +02:00
parent 2fa848b4a7
commit 14b165ff06
2 changed files with 279 additions and 168 deletions

View File

@@ -9,8 +9,7 @@ PROGRAM_NAME = f"Monitor_{SITE}"
import os, re, time, ssl, smtplib, logging
import datetime as dt
from email.message import EmailMessage
from typing import List
from datetime import datetime
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv(usecwd=True), override=False)
@@ -41,6 +40,45 @@ if not log.handlers:
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
# ========= DB utils =========
def open_alert(conn, table_alertes: str, sonde: str, dt: datetime) -> bool:
"""
Ouvre UNE alerte si aucune alerte 'En cours' n'existe encore pour la sonde.
Retourne True si une nouvelle alerte a été créée (→ notifier).
"""
cur = conn.cursor()
cur.execute(
f"SELECT 1 FROM `{table_alertes}` WHERE Sonde=%s AND Etat='En cours' LIMIT 1",
(sonde,)
)
if cur.fetchone():
cur.close()
return False # déjà ouverte → pas de notif
cur.execute(
f"INSERT INTO `{table_alertes}` (Sonde, Debut_defaut, Etat) VALUES (%s, %s, 'En cours')",
(sonde, dt.strftime('%Y-%m-%d %H:%M:%S'))
)
conn.commit()
cur.close()
return True # nouvelle alerte → notifier
def close_alert(conn, table_alertes: str, sonde: str) -> bool:
"""
Ferme l'alerte 'En cours' si présente.
Retourne True si une alerte est passée à 'Acquitté' (→ notifier).
"""
cur = conn.cursor()
cur.execute(
f"UPDATE `{table_alertes}` SET Etat='Acquitté' "
f"WHERE Sonde=%s AND Etat='En cours' "
f"ORDER BY Debut_defaut DESC LIMIT 1",
(sonde,)
)
changed = (cur.rowcount == 1)
conn.commit()
cur.close()
return changed # True → notifier, False → rien
def get_db():
cnx = mysql.connector.connect(
host=os.getenv("DB_HOST"),
@@ -136,19 +174,6 @@ def depassement_depuis_30min(site: str, sonde: str, seuil: float) -> bool:
finally:
cnx.close()
def alerte_en_cours(site: str, sonde: str) -> bool:
table = f"Alertes_{site}"
cnx = get_db()
try:
cur = cnx.cursor()
cur.execute(f"SELECT 1 FROM `{table}` WHERE `Sonde`=%s AND `Etat`='En cours' LIMIT 1", (sonde,))
return cur.fetchone() is not None
except MySQLError as err:
log.exception("Erreur DB (alerte_en_cours): %s", err)
return False
finally:
cnx.close()
def any_alert_open(site: str) -> bool:
table = f"Alertes_{site}"
cnx = get_db()
@@ -161,31 +186,6 @@ def any_alert_open(site: str) -> bool:
return False
finally:
cnx.close()
def creer_alerte(site: str, sonde: str):
table = f"Alertes_{site}"
cnx = get_db()
try:
cur = cnx.cursor()
cur.execute(f"INSERT INTO `{table}` (`Sonde`, `Debut_defaut`, `Etat`) VALUES (%s, NOW(), 'En cours')", (sonde,))
cnx.commit()
except MySQLError as err:
log.exception("Erreur DB (creer_alerte): %s", err)
finally:
cnx.close()
def acquitter_alerte(site: str, sonde: str):
table = f"Alertes_{site}"
cnx = get_db()
try:
cur = cnx.cursor()
cur.execute(f"UPDATE `{table}` SET `Etat`='Acquitté' WHERE `Sonde`=%s AND `Etat`='En cours'", (sonde,))
cnx.commit()
except MySQLError as err:
log.exception("Erreur DB (acquitter_alerte): %s", err)
finally:
cnx.close()
# ========= Helpers listes/numéros =========
def _split_list(raw: str | None) -> list[str]:
return [x.strip() for x in re.split(r"[;,]", raw or "") if x.strip()]
@@ -454,13 +454,29 @@ def run_monitor_cycle(site: str = SITE):
sondes = lire_sondes_depuis_db(site)
seuils = lire_seuils_depuis_db(site)
for r in sondes:
nom = str(r["Sonde"]); temp = float(r["Temperature"]); seuil = float(seuils.get(nom, 6.0))
nom = str(r["Sonde"])
temp = float(r["Temperature"])
seuil = float(seuils.get(nom, 6.0))
now = now_paris()
if temp > seuil:
if depassement_depuis_30min(site, nom, seuil) and not alerte_en_cours(site, nom):
creer_alerte(site, nom); notifier_sur_depassement(site, nom, temp, seuil)
if depassement_depuis_30min(site, nom, seuil):
# Ouvrir si pas déjà ouvert → notifier seulement si ouverture réelle
try:
conn = get_db()
if open_alert(conn, f"Alertes_{site}", nom, now):
notifier_sur_depassement(site, nom, temp, seuil)
finally:
conn.close()
else:
if alerte_en_cours(site, nom):
acquitter_alerte(site, nom); notifier_acquittement(site, nom, temp, seuil)
# Fermer si ouvert → notifier seulement si fermeture réelle
try:
conn = get_db()
if close_alert(conn, f"Alertes_{site}", nom):
notifier_acquittement(site, nom, temp, seuil)
finally:
conn.close()
def run_monitor_loop(site: str = SITE, period_sec: int = 300):
log.info("%s démarré (site=%s, période=%ss) ✅", PROGRAM_NAME, site, period_sec)