Consolidation de Domo91 et cosmétique
This commit is contained in:
@@ -9,7 +9,7 @@ Principes :
|
||||
- DB_HOST / MQTT_HOST / SMTP_HOST : uniques (VPS unique)
|
||||
- Paramètres par site via env : MAIL_TO_{SITE}, ALERT_SMS_TO_{SITE}, etc.
|
||||
- Les alertes ne concernent QUE les sondes présentes dans Chambres_froides pour le site
|
||||
et avec Etat=ON et En_entretien=0.
|
||||
et avec Etat=ON .
|
||||
"""
|
||||
|
||||
import datetime as dt
|
||||
@@ -274,7 +274,7 @@ def lire_cfg_chambres(site: str):
|
||||
"""
|
||||
dbname = os.getenv("DB_NAME", "Sondes")
|
||||
sql = f"""
|
||||
SELECT Sonde, Temp_Max, Etat, En_entretien
|
||||
SELECT Sonde, Temp_Max, Etat
|
||||
FROM `{dbname}`.`Chambres_froides`
|
||||
WHERE Lieu=%s
|
||||
"""
|
||||
@@ -283,11 +283,10 @@ def lire_cfg_chambres(site: str):
|
||||
try:
|
||||
cur = cnx.cursor()
|
||||
cur.execute(sql, (site,))
|
||||
for sonde, temp_max, etat, en_entretien in cur.fetchall():
|
||||
for sonde, temp_max, etat in cur.fetchall():
|
||||
cfg[str(sonde)] = {
|
||||
"temp_max": float(temp_max),
|
||||
"active": str(etat).upper() == "ON",
|
||||
"entretien": bool(int(en_entretien or 0)),
|
||||
}
|
||||
return cfg
|
||||
except MySQLError as err:
|
||||
@@ -307,7 +306,7 @@ def compute_site_alarm(last_values: list[dict], cfg: dict[str, dict], hysteresis
|
||||
meta = cfg.get(sonde)
|
||||
if not meta:
|
||||
continue
|
||||
if (not meta["active"]) or meta["entretien"]:
|
||||
if not meta["active"]:
|
||||
continue
|
||||
temp = float(row["Temperature"])
|
||||
seuil = float(meta["temp_max"])
|
||||
@@ -315,6 +314,70 @@ def compute_site_alarm(last_values: list[dict], cfg: dict[str, dict], hysteresis
|
||||
return True, (sonde, temp, seuil)
|
||||
return False, None
|
||||
|
||||
def depassement_depuis_2min(site: str, window_min: int = 3, needed_points: int = 2):
|
||||
"""
|
||||
Retourne (active: bool, trigger: (sonde, temp, seuil) | None)
|
||||
active = True si une sonde dépasse son seuil sur au moins 'needed_points' mesures
|
||||
dans les 'window_min' dernières minutes.
|
||||
|
||||
window_min=3 rend le système tolérant aux petits décalages (ex: sonde en retard).
|
||||
needed_points=2 correspond à votre objectif "2 minutes" (sondes toutes les minutes).
|
||||
"""
|
||||
table = safe_site(site)
|
||||
dbname = os.getenv("DB_NAME", "Sondes")
|
||||
|
||||
cnx = get_db()
|
||||
try:
|
||||
cur = cnx.cursor()
|
||||
|
||||
# 1) Cherche une sonde qui dépasse >=2 fois dans la fenêtre
|
||||
cur.execute(f"""
|
||||
SELECT m.Sonde
|
||||
FROM `{table}` m
|
||||
JOIN `{dbname}`.`Chambres_froides` c
|
||||
ON c.Lieu=%s
|
||||
AND c.Sonde=m.Sonde
|
||||
AND UPPER(c.Etat)='ON'
|
||||
WHERE m.Date >= NOW() - INTERVAL %s MINUTE
|
||||
AND m.Temperature IS NOT NULL
|
||||
AND m.Temperature > c.Temp_Max
|
||||
GROUP BY m.Sonde
|
||||
HAVING COUNT(*) >= %s
|
||||
LIMIT 1
|
||||
""", (site, window_min, needed_points))
|
||||
|
||||
row = cur.fetchone()
|
||||
if not row:
|
||||
return False, None
|
||||
|
||||
sonde = str(row[0])
|
||||
|
||||
# 2) Récupère dernière température + seuil pour le trigger
|
||||
cur.execute(f"""
|
||||
SELECT m.Temperature, c.Temp_Max
|
||||
FROM `{table}` m
|
||||
JOIN `{dbname}`.`Chambres_froides` c
|
||||
ON c.Lieu=%s AND c.Sonde=%s
|
||||
WHERE m.Sonde=%s
|
||||
AND m.Temperature IS NOT NULL
|
||||
ORDER BY m.Date DESC
|
||||
LIMIT 1
|
||||
""", (site, sonde, sonde))
|
||||
|
||||
trow = cur.fetchone()
|
||||
if not trow:
|
||||
return True, (sonde, 0.0, 0.0)
|
||||
|
||||
temp = float(trow[0])
|
||||
seuil = float(trow[1])
|
||||
return True, (sonde, temp, seuil)
|
||||
|
||||
except MySQLError as err:
|
||||
log.exception("Erreur DB (depassement_depuis_2min): %s", err)
|
||||
return False, None
|
||||
finally:
|
||||
cnx.close()
|
||||
|
||||
|
||||
def depassement_depuis_30min(site: str, sonde: str, seuil: float) -> bool:
|
||||
"""
|
||||
@@ -820,9 +883,10 @@ class GyroPulseController:
|
||||
self._last_trigger = None
|
||||
|
||||
def _is_alarm_now(self) -> tuple[bool, tuple[str, float, float] | None]:
|
||||
last_rows = lire_sondes_depuis_db(self.site)
|
||||
cfg = lire_cfg_chambres(self.site)
|
||||
return compute_site_alarm(last_rows, cfg, hysteresis=float(os.getenv("GYRO_HYSTERESIS", "0.0")))
|
||||
# Déclenchement "2 minutes" (2 points au-dessus du seuil sur ~3 minutes)
|
||||
window_min = int(os.getenv("GYRO_WINDOW_MIN", "3"))
|
||||
needed = int(os.getenv("GYRO_NEEDED_POINTS", "2"))
|
||||
return depassement_depuis_2min(self.site, window_min=window_min, needed_points=needed)
|
||||
|
||||
def _run(self):
|
||||
while not self._stop.is_set():
|
||||
@@ -944,7 +1008,7 @@ def run_monitor_cycle(site: str, notifier: Notifier):
|
||||
meta = cfg.get(nom)
|
||||
if not meta:
|
||||
continue
|
||||
if (not meta["active"]) or meta["entretien"]:
|
||||
if not meta["active"]:
|
||||
continue
|
||||
|
||||
seuil = float(meta["temp_max"])
|
||||
|
||||
Reference in New Issue
Block a user