diff --git a/.gitignore b/.gitignore deleted file mode 100644 index c42663a..0000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# --- Environnements virtuels --- -.venv/ -env/ - -# --- Python cache & compilés --- -__pycache__/ -*.py[cod] -*.log - -# --- IDEs (PyCharm, VSCode) --- -.idea/ -.vscode/ - -# --- fichiers système --- -.DS_Store -Thumbs.db - -# --- fichiers de test ou temporaires --- -*.bak -*.swp -*.tmp -*.old - -# --- Fichiers spécifiques si besoin --- -README.md.md -nv/ \ No newline at end of file diff --git a/Alerte_journalière.py b/Alerte_journalière.py deleted file mode 100644 index d2152d2..0000000 --- a/Alerte_journalière.py +++ /dev/null @@ -1,66 +0,0 @@ -import mysql.connector -from datetime import datetime -import smtplib -from email.mime.text import MIMEText - -# --- Config base de données --- -config = { - "host": "54.36.188.119", - "user": "michel", - "password": "#SO2&1nf%mZ@jfh", - "database": "Sondes" -} - -# --- Config email --- -def envoyer_mail(sujet, message, destinataires): - msg = MIMEText(message, "plain", "utf-8") - msg['Subject'] = sujet - msg['From'] = 'alertes_saclay@domo91.fr' - msg['To'] = ', '.join(destinataires) - - try: - with smtplib.SMTP_SSL('smtp.mail.ovh.net', 465) as server: - server.login('alertes_saclay@domo91.fr', 'Kdpke674y23Feq^H') - server.sendmail(msg['From'], destinataires, msg.as_string()) - print("📧 Mail récapitulatif envoyé avec succès.") - except Exception as e: - print(f"Erreur envoi mail : {e}") - -# --- Exécution principale --- -try: - conn = mysql.connector.connect(**config) - cursor = conn.cursor(dictionary=True) - - # Rechercher toutes les tables d'alertes - cursor.execute("SHOW TABLES LIKE 'Alertes_%'") - tables = [list(row.values())[0] for row in cursor.fetchall()] - - message = "" - total_alertes = 0 - - for table in tables: - lieu = table.replace("Alertes_", "") - cursor.execute(f"SELECT Sonde, Debut_defaut FROM {table} WHERE Status = 'En cours'") - alertes = cursor.fetchall() - - if alertes: - message += f"\n📍 **Site : {lieu}**\n" - for alerte in alertes: - debut = alerte['Debut_defaut'].strftime("%Y-%m-%d %H:%M") - message += f"🔔 Sonde : {alerte['Sonde']} | Depuis : {debut}\n" - total_alertes += len(alertes) - - if total_alertes > 0: - envoyer_mail( - sujet="🚨 Récapitulatif des alertes en cours - 7h00", - message=message, - destinataires=["services@domo91.fr"] - ) - else: - print("✅ Aucune alerte en cours à 7h00.") - - cursor.close() - conn.close() - -except Exception as e: - print(f"Erreur script alerte journalière : {e}") diff --git a/Chat-Id.py b/Chat-Id.py deleted file mode 100644 index a5bd401..0000000 --- a/Chat-Id.py +++ /dev/null @@ -1,36 +0,0 @@ -import requests -import json - -# Remplace par ton token de bot Telegram -token = "8128378340:AAF2sO3gaH1XpMNya_pEslzerqokoCiFRGs" - -url = f"https://api.telegram.org/bot{token}/getUpdates" - -try: - response = requests.get(url) - data = response.json() - - print("🔍 Récupération des chats Telegram récents...\n") - - if "result" in data: - chats = set() - - for update in data["result"]: - message = update.get("message") or update.get("edited_message") - if not message: - continue - - chat = message["chat"] - chat_id = chat["id"] - chat_title = chat.get("title") or chat.get("username") or chat.get("first_name") or "Inconnu" - - if chat_id not in chats: - chats.add(chat_id) - print(f"➡️ Chat : {chat_title} | ID : {chat_id}") - - if not chats: - print("⚠️ Aucun chat trouvé. Envoie un message depuis un groupe ou une discussion avec le bot.") - else: - print("❌ Erreur : aucune donnée 'result' trouvée dans la réponse.") -except Exception as e: - print(f"Erreur lors de la récupération des chats : {e}") diff --git a/Chaufferie.py b/Chaufferie.py deleted file mode 100644 index 73eab00..0000000 --- a/Chaufferie.py +++ /dev/null @@ -1,30 +0,0 @@ -import paho.mqtt.client as mqtt -import mysql.connector - -# Configuration de la connexion MySQL -mydb = mysql.connector.connect( - host="54.36.188.119", - user="michel", - password="#SO2&1nf%mZ@jfh", - database="Sondes" -) - -# Fonction de callback quand un message est reçu -def on_message(_client, _userdata, msg): - print(f"Message reçu sur {msg.topic}: {msg.payload.decode()}") - cursor = mydb.cursor() - frigo_name = msg.topic.split('/')[-1] # Prend la dernière partie après le "/" - sql = "INSERT INTO Chaufferie (Sonde, Temperature) VALUES (%s, %s)" - val = (frigo_name, msg.payload.decode()) - cursor.execute(sql, val) - mydb.commit() - -# Configuration du client MQTT -client = mqtt.Client() -client.username_pw_set("Bwps", "scJ5ACj2keRfI^") -client.on_message = on_message - -client.connect("54.36.188.119", 1883, 60) -client.subscribe("Module_01/#") # S'abonner à tous les topics commençant par Saclay - -client.loop_forever() # Rester connecté en continu pour écouter les messages diff --git a/Connexion_mysql.py b/Connexion_mysql.py deleted file mode 100644 index 53c7c10..0000000 --- a/Connexion_mysql.py +++ /dev/null @@ -1,9 +0,0 @@ -import mysql.connector - -conn = mysql.connector.connect( - host="54.36.188.119", - user="michel", - password="#SO2&1nf%mZ@jfh", - database="Sondes" -) -print("Connexion OK") \ No newline at end of file diff --git a/Cuisine_meudon.py b/Cuisine_meudon.py deleted file mode 100644 index e8c1b05..0000000 --- a/Cuisine_meudon.py +++ /dev/null @@ -1,30 +0,0 @@ -import paho.mqtt.client as mqttClient -client = mqttClient.Client() -import mysql.connector -import sys -sys.path.insert(0, "/myenv/lib/python3.11.2/site-packages") - -# Configuration de la connexion MySQL -mydb = mysql.connector.connect( - host="54.36.188.119", - user="michel", - password="#SO2&1nf%mZ@jfh", - database="Sondes" -) - -# Fonction de callback quand un message est reçu -def on_message(_client, _userdata, msg): - print(f"Message reçu sur {msg.topic}: {msg.payload.decode()}") - cursor = mydb.cursor() - frigo_name = msg.topic.split('/')[-1] # Prend la dernière partie après le "/" - sql = "INSERT INTO Meudon (Sonde, Temperature) VALUES (%s, %s)" - val = (frigo_name, msg.payload.decode()) - cursor.execute(sql, val) - mydb.commit() - -# Configuration du client MQTT -client.username_pw_set("Bwps", "scJ5ACj2keRfI^") -client.on_message = on_message -client.connect("54.36.188.119", 1883, 60) -client.subscribe("Meudon/#") # S'abonner à tous les topics commençant par Saclay -client.loop_forever() # Rester connecté en continu pour écouter les messages diff --git a/Cuisine_saclay.py b/Cuisine_saclay.py deleted file mode 100644 index 4e68428..0000000 --- a/Cuisine_saclay.py +++ /dev/null @@ -1,30 +0,0 @@ -import paho.mqtt.client as mqttClient -client = mqttClient.Client() -import mysql.connector -import sys -sys.path.insert(0, "/myenv/lib/python3.11.2/site-packages") - -# Configuration de la connexion MySQL -mydb = mysql.connector.connect( - host="54.36.188.119", - user="michel", - password="#SO2&1nf%mZ@jfh", - database="Sondes" -) - -# Fonction de callback quand un message est reçu -def on_message(_client, _userdata, msg): - print(f"Message reçu sur {msg.topic}: {msg.payload.decode()}") - cursor = mydb.cursor() - frigo_name = msg.topic.split('/')[-1] # Prend la dernière partie après le "/" - sql = "INSERT INTO Saclay (Sonde, Temperature) VALUES (%s, %s)" - val = (frigo_name, msg.payload.decode()) - cursor.execute(sql, val) - mydb.commit() - -# Configuration du client MQTT -client.username_pw_set("Bwps", "scJ5ACj2keRfI^") -client.on_message = on_message -client.connect("54.36.188.119", 1883, 60) -client.subscribe("Saclay/#") # S'abonner à tous les topics commençant par Saclay -client.loop_forever() # Rester connecté en continu pour écouter les messages diff --git a/Documentation_Systeme_Domo91.pdf b/Documentation_Systeme_Domo91.pdf deleted file mode 100644 index 561b3c2..0000000 Binary files a/Documentation_Systeme_Domo91.pdf and /dev/null differ diff --git a/Général.py b/Général.py deleted file mode 100644 index 9ddce6c..0000000 --- a/Général.py +++ /dev/null @@ -1,323 +0,0 @@ -import requests -import mysql.connector -from datetime import datetime, timedelta -import time -import sys -import os -import schedule - -def connect_db(): - return mysql.connector.connect( - host="54.36.188.119", - user="michel", - password="#SO2&1nf%mZ@jfh", - database="Sondes" - ) - -def envoi_etat_quotidien(cursor, site): - token = "5714323406:AAGSj9jrfBHbfxubz3ooabPEizI8aBOLnvE" - chat_id = get_chat_id(cursor, site) - etat_sondes(cursor, site, chat_id, token) - print(f"[INFO] État des sondes envoyé pour le site {site}.") - -def get_active_sondes(cursor, site): - query = "SELECT Sonde, Temp_Max FROM Chambres_froides WHERE Lieu = %s AND Etat = 'On';" - cursor.execute(query, (site,)) - result = cursor.fetchall() - return {row[0]: float(row[1]) for row in result} - - -def check_temperature_limits(cursor, table_historique, sonde, limite, duree=30): - temps_limite = datetime.now() - timedelta(minutes=duree) - query = f""" - SELECT Temperature - FROM {table_historique} - WHERE Sonde = %s AND Date >= %s - ORDER BY Date DESC LIMIT 6; - """ - cursor.execute(query, (sonde, temps_limite)) - result = cursor.fetchall() - if len(result) == 6 and all(float(temp[0]) > limite for temp in result): - return True, float(result[0][0]) - return False, None - -def simulate_alert(db, cursor, site, sonde, chat_id, token): - table_alertes = f"Alertes_{site}" - print(f"[TEST] tentative d'insertion de sonde : {sonde} dans table {table_alertes}") - - try: - query = f""" - INSERT INTO {table_alertes} (Sonde, Debut_defaut, Status) - VALUES (%s, NOW(), 'test') - ON DUPLICATE KEY UPDATE Debut_defaut = NOW(), Status = 'test'; - """ - cursor.execute(query, (sonde,)) - db.commit() - print(f"[TEST] insertion ou mise à jour réussie pour {sonde}.") - except Exception as e: - print(f"[ERREUR] lors de l'insertion test : {e}") - - message = f"⚠️ TEST ALERTE : Simulation d'une alerte pour la sonde {sonde}." - url = f"https://api.telegram.org/bot{token}/sendMessage" - try: - requests.get(url, params={'chat_id': chat_id, 'text': message}) - except Exception as e: - print(f"[ERREUR] lors de l'envoi Telegram : {e}") - -def create_alert(db, cursor, table_alertes, sonde, temperature): - query = f""" - INSERT INTO {table_alertes} (Sonde, Debut_defaut, Status) - VALUES (%s, NOW(), 'en cours'); - """ - cursor.execute(query, (sonde,)) - send_telegram_message(sonde, temperature) - print(f"Alerte créée pour la sonde {sonde}") - db.commit() - -def resolve_alert(cursor, table_alertes, sonde): - query = f""" - UPDATE {table_alertes} - SET Status = 'résolu' - WHERE Sonde = %s AND Status = 'en cours'; - """ - cursor.execute(query, (sonde,)) - print(f"Alerte résolue pour la sonde {sonde}") - -def acquitter_alerte(cursor, site, sonde, chat_id, token): - table_alertes = f"Alertes_{site}" - query = f""" - UPDATE {table_alertes} - SET Status = 'acquittée' - WHERE Sonde = %s AND Status IN ('en cours', 'test'); - """ - cursor.execute(query, (sonde,)) - lignes_modifiees = cursor.rowcount - - if lignes_modifiees > 0: - message = f"✅ Alerte acquittée pour la sonde {sonde} par commande Telegram." - else: - message = f"ℹ️ Aucune alerte active à acquitter pour la sonde {sonde}." - - url = f"https://api.telegram.org/bot{token}/sendMessage" - try: - requests.get(url, params={'chat_id': chat_id, 'text': message}) - except Exception as e: - print(f"[ERREUR] envoi message Telegram : {e}") - -def send_telegram_message(sonde, temperature): - token = "5714323406:AAGSj9jrfBHbfxubz3ooabPEizI8aBOLnvE" - chat_id = "-1002442631825" - message = f"⚠️ Alerte température : La sonde {sonde} dépasse la limite avec une température de {temperature}°C." - url = f"https://api.telegram.org/bot{token}/sendMessage" - params = {'chat_id': chat_id, 'text': message} - try: - response = requests.get(url, params=params) - if response.status_code == 200: - print(f"Message envoyé via Telegram pour la sonde {sonde}.") - else: - print(f"Erreur lors de l'envoi du message Telegram : {response.status_code}") - except Exception as e: - print(f"Erreur lors de l'envoi du message Telegram : {e}") - - -def get_chat_id(cursor, site): - cursor.execute("SELECT Chat_ID FROM Sites WHERE Nom = %s;", (site,)) - result = cursor.fetchone() - if result: - return result[0] - else: - print(f"Aucun Chat_ID trouvé pour le site {site}") - return None - -def passer_en_maintenance(cursor, site, sonde, chat_id, token): - try: - query = """ - UPDATE Chambres_froides - SET Etat = 'Off' - WHERE Lieu = %s AND Sonde = %s; - """ - cursor.execute(query, (site, sonde)) - lignes_modifiees = cursor.rowcount - - if lignes_modifiees > 0: - message = f"🛠️ La sonde {sonde} a été passée en mode maintenance (OFF)." - else: - message = f"⚠️ Sonde {sonde} introuvable pour le site {site}." - - url = f"https://api.telegram.org/bot{token}/sendMessage" - requests.get(url, params={'chat_id': chat_id, 'text': message}) - - except Exception as e: - print(f"[ERREUR] lors du passage en maintenance : {e}") - -def reactiver_sonde(cursor, site, sonde, chat_id, token): - try: - query = """ - UPDATE Chambres_froides - SET Etat = 'On' - WHERE Lieu = %s AND Sonde = %s; - """ - cursor.execute(query, (site, sonde)) - lignes_modifiees = cursor.rowcount - - if lignes_modifiees > 0: - message = f"✅ La sonde {sonde} a été réactivée (ON)." - else: - message = f"⚠️ Sonde {sonde} introuvable pour le site {site}." - - url = f"https://api.telegram.org/bot{token}/sendMessage" - requests.get(url, params={'chat_id': chat_id, 'text': message}) - - except Exception as e: - print(f"[ERREUR] lors de la réactivation : {e}") - -def etat_sondes(cursor, site, chat_id, token): - query = "SELECT Sonde, Etat FROM Chambres_froides WHERE Lieu = %s ORDER BY Sonde;" - cursor.execute(query, (site,)) - result = cursor.fetchall() - - message = f"📊 État des sondes - {site} :\n" - for sonde, etat in result: - symbole = "🟢" if etat.upper() == "ON" else "🔴" - message += f"{symbole} {sonde} ({etat.upper()})\n" - - url = f"https://api.telegram.org/bot{token}/sendMessage" - requests.get(url, params={'chat_id': chat_id, 'text': message}) - -def monitor_temperatures_simple(site, db, cursor): - table_historique = site - table_alertes = f"Alertes_{site}" - sondes = get_active_sondes(cursor, site) - print(f"[MONITORING] Sondes actives pour {site} : {sondes}") - - for sonde, limite in sondes.items(): - alert_needed, temperature = check_temperature_limits(cursor, table_historique, sonde, limite) - if alert_needed: - create_alert(db, cursor, table_alertes, sonde, temperature) - else: - resolve_alert(cursor, table_alertes, sonde) - - db.commit() - print("[MONITORING] Vérification des sondes terminée.") - -def monitor_temperatures(site): - db = connect_db() - cursor = db.cursor() - - table_historique = site # Ex: Saclay - table_alertes = f"Alertes_{site}" # Ex: Alertes_Saclay - - sondes = get_active_sondes(cursor, site) - print(f"Sondes actives pour le site {site} :", sondes) - - for sonde, limite in sondes.items(): - alert_needed, temperature = check_temperature_limits(cursor, table_historique, sonde, limite) - if alert_needed: - create_alert(db, cursor, table_alertes, sonde, temperature) - else: - resolve_alert(cursor, table_alertes, sonde) - - db.commit() - listen_for_commands(db, cursor, site) - cursor.close() - db.close() - -def listen_for_commands(db, cursor, site): - token = "5714323406:AAGSj9jrfBHbfxubz3ooabPEizI8aBOLnvE" - chat_id = get_chat_id(cursor, site) - offset_file = os.path.join(os.path.dirname(__file__), f"last_update_id_{site}.txt") - - try: - with open(offset_file, 'r') as f: - last_update_id = int(f.read().strip()) - except FileNotFoundError: - last_update_id = None - - url = f"https://api.telegram.org/bot{token}/getUpdates" - if last_update_id is not None: - url += f"?offset={last_update_id + 1}" - - try: - response = requests.get(url) - data = response.json() - - if "result" in data: - for update in data["result"]: - update_id = update["update_id"] - - if "message" in update: - message = update["message"]["text"] - print(f"[CMD] Message reçu : {message}") - - if message.lower().startswith("/etat"): - etat_sondes(cursor, site, chat_id, token) - - elif message.lower().startswith("/acquitter"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - acquitter_alerte(cursor, site, sonde, chat_id, token) - db.commit() - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /acquitter " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - elif message.lower().startswith("/maintenance"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - passer_en_maintenance(cursor, site, sonde, chat_id, token) - db.commit() - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /maintenance " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - elif message.lower().startswith("/reactiver"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - reactiver_sonde(cursor, site, sonde, chat_id, token) - db.commit() - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /reactiver " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - elif message.lower().startswith("/test"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - simulate_alert(db, cursor, site, sonde, chat_id, token) - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /test " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - - with open(offset_file, 'w') as f: - f.write(str(update_id)) - - except Exception as e: - print(f"Erreur lors de la lecture des commandes Telegram : {e}") - - -def main(): - site = sys.argv[1] if len(sys.argv) > 1 else "Saclay" - db = connect_db() - cursor = db.cursor() - - # ✅ Planification : tous les jours à 07:00 → état des sondes - schedule.every().day.at("07:00").do(envoi_etat_quotidien, cursor=cursor, site=site) - - # ✅ Planification : toutes les 2m30 → surveillance - schedule.every(2).minutes.do(monitor_temperatures_simple, site=site, db=db, cursor=cursor) - - try: - while True: - schedule.run_pending() - listen_for_commands(db, cursor, site) - time.sleep(2) # petite pause pour ne pas surcharger Telegram - finally: - cursor.close() - db.close() - -if __name__ == "__main__": - main() diff --git a/Monitor.py b/Monitor.py deleted file mode 100644 index 0a72774..0000000 --- a/Monitor.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/home/debian/travail/myenv/bin/python -# Surveillance continue avec envoi d'alertes par email + log CSV - -import mysql.connector -from datetime import datetime, timedelta -import time -import smtplib -from email.mime.text import MIMEText -import pandas as pd - -# --- Config MySQL --- -config = { - "host": "54.36.188.119", - "user": "michel", - "password": "#SO2&1nf%mZ@jfh", - "database": "Sondes" -} - -# --- Destinataires email --- -destinataires = ['services@domo91.fr'] - -# --- Fonction d'envoi de mail --- -def envoyer_mail(sujet, message, destinataires): - msg = MIMEText(message) - msg['Subject'] = sujet - msg['From'] = 'alertes_saclay@domo91.fr' - msg['To'] = ', '.join(destinataires) - try: - with smtplib.SMTP_SSL('smtp.mail.ovh.net', 465) as server: - server.login('alertes_saclay@domo91.fr', 'Kdpke674y23Feq^H') - server.sendmail(msg['From'], destinataires, msg.as_string()) - print(f"📧 Mail envoyé à {destinataires}", flush=True) - except Exception as e: - print(f"Erreur envoi mail : {e}", flush=True) - -# --- Fonction de surveillance --- -def surveiller(): - log_entries = [] - try: - conn = mysql.connector.connect(**config) - cursor = conn.cursor(dictionary=True) - - cursor.execute("SELECT DISTINCT Lieu FROM Chambres_froides") - lieux = [row['Lieu'] for row in cursor.fetchall()] - - for lieu in lieux: - table_temp = lieu - table_alertes = f"Alertes_{lieu}" - - cursor.execute("SELECT Sonde, Temp_Max FROM Chambres_froides WHERE Lieu=%s AND Etat='ON'", (lieu,)) - sondes = cursor.fetchall() - - for sonde in sondes: - nom_sonde = sonde['Sonde'] - seuil = sonde['Temp_Max'] - - cursor.execute(f""" - SELECT Date, Temperature FROM {table_temp} - WHERE Sonde = %s - ORDER BY Date DESC LIMIT 6 - """, (nom_sonde,)) - relevés = cursor.fetchall() - - # Log CSV : tous les relevés analysés - for r in relevés: - log_entries.append({ - "Date": r['Date'], - "Lieu": lieu, - "Sonde": nom_sonde, - "Température": r['Temperature'], - "Seuil": seuil, - "État": "Dépassement" if r['Temperature'] > seuil else "Normal" - }) - - if len(relevés) == 6: - toutes_hors_seuil = all(r['Temperature'] > seuil for r in relevés) - plus_ancien = relevés[-1]['Date'] - maintenant = datetime.now() - - if toutes_hors_seuil and (maintenant - plus_ancien >= timedelta(minutes=30)): - cursor.execute(f""" - SELECT COUNT(*) as total FROM {table_alertes} - WHERE Sonde=%s AND Status='En cours' - """, (nom_sonde,)) - en_cours = cursor.fetchone() - if en_cours['total'] == 0: - cursor.execute( - f"INSERT INTO {table_alertes} (Sonde, Debut_defaut, Status) VALUES (%s, NOW(), 'En cours')", - (nom_sonde,) - ) - print(f"🚨 Alerte déclenchée pour {nom_sonde} ({lieu})", flush=True) - sujet = f"🚨 ALERTE TEMPÉRATURE - {nom_sonde} ({lieu})" - message = ( - f"La sonde '{nom_sonde}' du site '{lieu}' a dépassé le seuil de {seuil}°C " - f"depuis plus de 30 minutes.\nHeure : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" - ) - envoyer_mail(sujet, message, destinataires) - - # Acquittement automatique - cursor.execute(f""" - SELECT Temperature FROM {table_temp} - WHERE Sonde = %s - ORDER BY Date DESC LIMIT 1 - """, (nom_sonde,)) - derniere = cursor.fetchone() - if derniere and derniere['Temperature'] <= seuil: - cursor.execute(f""" - UPDATE {table_alertes} - SET Status = 'Acquitté' - WHERE Sonde = %s AND Status = 'En cours' - """, (nom_sonde,)) - - conn.commit() - cursor.close() - conn.close() - - # Enregistrer le log - if log_entries: - df_logs = pd.DataFrame(log_entries) - df_logs.to_csv("/home/debian/travail/logs_monitor.csv", sep=";", index=False) - - except Exception as e: - print(f"Erreur : {e}", flush=True) - -# --- Boucle principale --- -while True: - print(f"📡 Vérification à {datetime.now()}", flush=True) - surveiller() - time.sleep(300) # 5 minutes diff --git a/Purge_Alertes_saclay.py b/Purge_Alertes_saclay.py deleted file mode 100644 index 72a5d1b..0000000 --- a/Purge_Alertes_saclay.py +++ /dev/null @@ -1,17 +0,0 @@ -import mysql.connector - -config = { - "host": "54.36.188.119", - "user": "michel", - "password": "#SO2&1nf%mZ@jfh", - "database": "Sondes" -} - -conn = mysql.connector.connect(**config) -cursor = conn.cursor() -cursor.execute("DELETE FROM Alertes_Saclay WHERE Debut_defaut < NOW() - INTERVAL 7 DAY") -conn.commit() -cursor.close() -conn.close() - -print("✅ Alertes de plus de 7 jours supprimées.") diff --git a/README.md b/README.md deleted file mode 100644 index a2aea93..0000000 --- a/README.md +++ /dev/null @@ -1,103 +0,0 @@ -# 📡 Gestion des sondes de température - Domo91 - -Application de supervision multi-sites pour chambres froides industrielles. - -## 🧩 Structure du projet - -- `Streamlit.py` : Interface Web (authentification, affichage des relevés, alertes) -- `Monitor.py` : Script de fond qui vérifie les seuils et envoie les alertes email -- `logs_monitor.csv` : Journal des températures (généré par Monitor) -- `Telegram_sondes.py` : (optionnel) Envoi des alertes sur Telegram -- `Chambres_froides` (MySQL) : Table de référence pour les seuils/états des sondes - -## ⚙️ Fonctionnalités principales - -- Authentification par rôle (utilisateur / superviseur) -- Visualisation interactive des relevés -- Détection automatique des dépassements prolongés -- Envoi d’alertes email automatisé -- Analyse graphique des relevés -- Admin : modification des seuils et activation/désactivation des sondes - -## 🗺️ Schéma d'architecture - -![Schéma d'architecture](A_flowchart_diagram_in_the_image_depicts_an_archit.png) - -## 🚀 Installation locale (PyCharm) - -1. Cloner le dépôt : - ```bash - git clone http://192.168.1.250:3000/nom_du_repo.git - ``` - -2. Créer l’environnement virtuel Python : - ```bash - python3 -m venv .venv - source .venv/bin/activate - pip install -r requirements.txt - ``` - -3. Lancer l'interface Streamlit : - ```bash - streamlit run Streamlit.py - ``` - -4. Lancer le script de fond manuellement : - ```bash - python Monitor.py - ``` - -## 🖥️ Installation sur le VPS - -1. Cloner le dépôt dans `/home/debian/travail` : - ```bash - git clone /home/debian/travail - ``` - -2. Créer l’environnement virtuel : - ```bash - cd /home/debian/travail - python3 -m venv venv - source venv/bin/activate - pip install -r requirements.txt - ``` - -## 🛠️ Supervisor - -Les services sont gérés par Supervisor : - -- `monitor` → `/home/debian/travail/Monitor.py` -- `streamlit` → `/home/debian/travail/Streamlit.py` - -Fichier exemple : `/etc/supervisor/conf.d/monitor.conf` -```ini -[program:monitor] -command=/home/debian/travail/venv/bin/python /home/debian/travail/Monitor.py -directory=/home/debian/travail -autostart=true -autorestart=true -stderr_logfile=/var/log/monitor.err.log -stdout_logfile=/var/log/monitor.out.log -``` - -Commandes utiles : -```bash -sudo supervisorctl status -sudo supervisorctl restart monitor -``` - -## 🧪 Vérification / Test - -- Tester MQTT : `mosquitto_pub -t test -m "message"` -- Simuler une alerte : forcer une température > seuil pendant 30 minutes -- Vérifier les emails : vérifier logs ou boîte de réception -- Tester Streamlit : se connecter avec différents rôles utilisateur - -## 🔒 Accès - -- Interface Web : [https://app.domo91.fr](https://app.domo91.fr) -- Administration Git : [http://192.168.1.250:3000](http://192.168.1.250:3000) - -## 👤 Auteur - -Michel — [michel@domo91.fr](mailto:michel@domo91.fr) diff --git a/Scripts/Redémarrage.sh b/Scripts/Redémarrage.sh deleted file mode 100644 index b11e5e3..0000000 --- a/Scripts/Redémarrage.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Fonction pour vérifier et relancer un processus -check_and_restart() { - process_name="$1" - log_file="$2" - script_path="$3" - - # Vérifier si le processus est actif - if pgrep -af "$process_name" > /dev/null; then - echo "Le processus $process_name est actif." - else - echo "Le processus $process_name est mort." - - # Demander à l'utilisateur s'il souhaite relancer le processus - read -p "Voulez-vous relancer le processus $process_name ? (O/N) " choice - if [ "$choice" = "O" ] || [ "$choice" = "o" ]; then - echo "Relancer le processus $process_name." - nohup python3 $script_path > $log_file 2>&1 & - else - echo "Ne rien faire pour le processus $process_name." - fi - fi -} - -# Afficher les processus Python3 actifs et les vérifier -echo "Vérification des processus Python3 :" -check_and_restart "Cuisine.py" "/root/python/log/cuisine_saclay_output.log" "/root/python/Cuisine_saclay.py" -check_and_restart "Chaufferie.py" "/root/python/log/chaufferie_output.log" "/root/python/Chaufferie.py" -check_and_restart "Alertes_telegram.py" "/root/python/log/Alertes_telegram_output.log" "/root/python/Alertes_telegram.py" diff --git a/Scripts/backup_mysql.sh b/Scripts/backup_mysql.sh deleted file mode 100644 index 8bfdf53..0000000 --- a/Scripts/backup_mysql.sh +++ /dev/null @@ -1,3 +0,0 @@ -# mysqldump --defaults-file=/root/my.cnf -u michel Sondes > /root/syno/Sondes-$(date +%Y%m%d).sql -# mysqldump --defaults-file=/root/my.cnf -u michel --databases Sondes Best_Western >/root/syno/BW-$(date +%Y%m%d).sql -mysqldump --defaults-file=/root/my.cnf -u michel --databases Best_Western Sondes >/root/syno/BW-$(date +%Y%m%d).sql diff --git a/Scripts/check_docker.sh b/Scripts/check_docker.sh deleted file mode 100644 index 5d0a06d..0000000 --- a/Scripts/check_docker.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# Fonction pour vérifier et redémarrer un container Docker -check_and_restart_container() { - container_name="$1" - - # Vérifier si le container est en cours d'exécution - if docker ps --format '{{.Names}}' | grep -q "$container_name"; then - echo "Le container $container_name est en cours d'exécution." - else - echo "Le container $container_name n'est pas en cours d'exécution." - - # Demander à l'utilisateur s'il souhaite redémarrer le container - read -p "Voulez-vous redémarrer le container $container_name ? (O/N) " choice - if [ "$choice" = "O" ] || [ "$choice" = "o" ]; then - echo "Redémarrer le container $container_name." - docker restart $container_name - else - echo "Ne rien faire pour le container $container_name." - fi - fi -} - -# Afficher les containers Docker actifs et les vérifier -echo "Vérification des containers Docker :" -check_and_restart_container "domoticz" -check_and_restart_container "postfix" diff --git a/Scripts/verifie_scripts.sh b/Scripts/verifie_scripts.sh deleted file mode 100644 index aa833e5..0000000 --- a/Scripts/verifie_scripts.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# Fonction pour vérifier et relancer un processus -check_and_restart() { - process_name="$1" - log_file="$2" - - # Vérifier si le processus est actif - if pgrep -af "$process_name" > /dev/null; then - echo "Le processus $process_name est actif." - else - echo "Le processus $process_name est mort." - - # Demander à l'utilisateur s'il souhaite relancer le processus - read -p "Voulez-vous relancer le processus $process_name ? (O/N) " choice - if [ "$choice" = "O" ] || [ "$choice" = "o" ]; then - echo "Relancer le processus $process_name." - nohup $process_name > $log_file 2>&1 & - else - echo "Ne rien faire pour le processus $process_name." - fi - fi -} - -# Afficher les processus Python3 actifs et les vérifier -echo "Vérification des processus Python3 :" -check_and_restart "python3 /root/python/Cuisine_saclay.py" "/root/python/log/cuisine_saclay_output.log" -check_and_restart "python3 /root/python/Chaufferie.py" "/root/python/log/chaufferie_output.log" -check_and_restart "python3 /root/python/Alertes_telegram.py" "/root/python/log/Alertes_telegram_output.log" diff --git a/Streamlit.py b/Streamlit.py deleted file mode 100644 index 0c7fa0e..0000000 --- a/Streamlit.py +++ /dev/null @@ -1,237 +0,0 @@ -# Application Streamlit avec coloration rouge des températures dépassant les seuils dans logs - -import streamlit as st -import mysql.connector -import pandas as pd -from datetime import date -import matplotlib.pyplot as plt -import matplotlib.dates as mdates - -st.set_page_config(page_title="Domo91 - Surveillance", layout="wide") -st.title("📡 Supervision Températures Multisites") - -# --- Configuration base de données --- -db_config = { - "host": "54.36.188.119", - "user": "michel", - "password": "#SO2&1nf%mZ@jfh", - "database": "Sondes" -} - -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() - - -with st.sidebar: - st.markdown("# 🌡️ **Domo91**") - st.markdown("Monitoring chambres froides industrielles") - st.header("🔐 Connexion") - if not st.session_state["authenticated"]: - login = st.text_input("Nom d'utilisateur") - password = st.text_input("Mot de passe", type="password") - if st.button("Se connecter"): - try: - conn = mysql.connector.connect(**db_config) - cursor = conn.cursor(dictionary=True) - cursor.execute("SELECT * FROM MotsDePasse WHERE utilisateur = %s", (login,)) - result = cursor.fetchone() - if result and result["mot_de_passe"] == password: - st.session_state["authenticated"] = True - st.session_state["role"] = result["role"] - st.session_state["lieu_autorise"] = result["Lieu"] - st.success(f"Connecté comme {result['role']} ({result['Lieu']})") - else: - st.error("Identifiants invalides") - cursor.close() - conn.close() - except Exception as e: - st.error(f"Erreur lors de la connexion à la base : {e}") - else: - st.success(f"Connecté ({st.session_state['role']})") - if st.button("🔓 Déconnexion"): - st.session_state["authenticated"] = False - st.session_state["role"] = None - st.session_state["lieu_autorise"] = None - st.rerun() - -# --- Interface principale -if st.session_state["authenticated"]: - try: - conn = mysql.connector.connect(**db_config) - cursor = conn.cursor(dictionary=True) - sites_possibles = ["Saclay", "Meudon"] - if st.session_state["role"] == "superviseur": - site_selectionne = st.selectbox("📍 Choisissez un site :", sites_possibles) - 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()) - cursor.execute( - f"SELECT * FROM `{site_selectionne}` WHERE DATE(Date) = %s ORDER BY Sonde, Date", - (selected_date.strftime("%Y-%m-%d"),) - ) - rows = cursor.fetchall() - if rows: - df = pd.DataFrame(rows) - df["Date"] = pd.to_datetime(df["Date"]) - sondes = sorted(df["Sonde"].unique()) - sonde_choisie = st.selectbox("🧪 Choisissez une sonde :", sondes) - df_sonde = df[df["Sonde"] == sonde_choisie].copy() - df_sonde["Heure"] = df_sonde["Date"].dt.hour - - # 🕓 Filtres horaires - st.markdown("### 🕒 Filtrer par moment de la journée") - col1, col2, col3 = st.columns(3) - filtre_matin = col1.checkbox("Matin (06h-12h)", value=True) - filtre_apresmidi = col2.checkbox("Après-midi (12h-18h)", value=True) - filtre_nuit = col3.checkbox("Nuit (18h-06h)", value=True) - - # Construction du filtre combiné - filtres = [] - if filtre_matin: - filtres.append(df_sonde["Heure"].between(6, 11)) - if filtre_apresmidi: - filtres.append(df_sonde["Heure"].between(12, 17)) - if filtre_nuit: - filtres.append((df_sonde["Heure"] >= 18) | (df_sonde["Heure"] < 6)) - - if filtres: - filtre_combiné = filtres[0] - for f in filtres[1:]: - filtre_combiné |= f - df_sonde = df_sonde[filtre_combiné] - 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 - st.dataframe(df_sonde, use_container_width=True) - st.subheader("📈 Évolution de la température") - fig, ax = plt.subplots(figsize=(10, 4)) - ax.plot(df_sonde["Date"], df_sonde["Temperature"], marker='o', label="Température") - ax.axhline(seuil_temp, color='red', linestyle='--', label=f"Seuil {seuil_temp}°C") - ax.set_xlabel("Heure") - ax.set_ylabel("Température (°C)") - ax.set_title(f"{sonde_choisie} - {selected_date.strftime('%d/%m/%Y')}") - 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 diff --git a/Telegram_sondes.py b/Telegram_sondes.py deleted file mode 100644 index f89a4cb..0000000 --- a/Telegram_sondes.py +++ /dev/null @@ -1,323 +0,0 @@ -import requests -import mysql.connector -from datetime import datetime, timedelta -import time -import sys -import os -import schedule - -def connect_db(): - return mysql.connector.connect( - host="54.36.188.119", - user="michel", - password="#SO2&1nf%mZ@jfh", - database="Sondes" - ) - -def envoi_etat_quotidien(cursor, site): - token = "8128378340:AAF2sO3gaH1XpMNya_pEslzerqokoCiFRGs" - chat_id = get_chat_id(cursor, site) - etat_sondes(cursor, site, chat_id, token) - print(f"[INFO] État des sondes envoyé pour le site {site}.") - -def get_active_sondes(cursor, site): - query = "SELECT Sonde, Temp_Max FROM Chambres_froides WHERE Lieu = %s AND Etat = 'On';" - cursor.execute(query, (site,)) - result = cursor.fetchall() - return {row[0]: float(row[1]) for row in result} - - -def check_temperature_limits(cursor, table_historique, sonde, limite, duree=30): - temps_limite = datetime.now() - timedelta(minutes=duree) - query = f""" - SELECT Temperature - FROM {table_historique} - WHERE Sonde = %s AND Date >= %s - ORDER BY Date DESC LIMIT 6; - """ - cursor.execute(query, (sonde, temps_limite)) - result = cursor.fetchall() - if len(result) == 6 and all(float(temp[0]) > limite for temp in result): - return True, float(result[0][0]) - return False, None - -def simulate_alert(db, cursor, site, sonde, chat_id, token): - table_alertes = f"Alertes_{site}" - print(f"[TEST] tentative d'insertion de sonde : {sonde} dans table {table_alertes}") - - try: - query = f""" - INSERT INTO {table_alertes} (Sonde, Debut_defaut, Status) - VALUES (%s, NOW(), 'test') - ON DUPLICATE KEY UPDATE Debut_defaut = NOW(), Status = 'test'; - """ - cursor.execute(query, (sonde,)) - db.commit() - print(f"[TEST] insertion ou mise à jour réussie pour {sonde}.") - except Exception as e: - print(f"[ERREUR] lors de l'insertion test : {e}") - - message = f"⚠️ TEST ALERTE : Simulation d'une alerte pour la sonde {sonde}." - url = f"https://api.telegram.org/bot{token}/sendMessage" - try: - requests.get(url, params={'chat_id': chat_id, 'text': message}) - except Exception as e: - print(f"[ERREUR] lors de l'envoi Telegram : {e}") - -def create_alert(db, cursor, table_alertes, sonde, temperature): - query = f""" - INSERT INTO {table_alertes} (Sonde, Debut_defaut, Status) - VALUES (%s, NOW(), 'en cours'); - """ - cursor.execute(query, (sonde,)) - send_telegram_message(sonde, temperature) - print(f"Alerte créée pour la sonde {sonde}") - db.commit() - -def resolve_alert(cursor, table_alertes, sonde): - query = f""" - UPDATE {table_alertes} - SET Status = 'résolu' - WHERE Sonde = %s AND Status = 'en cours'; - """ - cursor.execute(query, (sonde,)) - print(f"Alerte résolue pour la sonde {sonde}") - -def acquitter_alerte(cursor, site, sonde, chat_id, token): - table_alertes = f"Alertes_{site}" - query = f""" - UPDATE {table_alertes} - SET Status = 'acquittée' - WHERE Sonde = %s AND Status IN ('en cours', 'test'); - """ - cursor.execute(query, (sonde,)) - lignes_modifiees = cursor.rowcount - - if lignes_modifiees > 0: - message = f"✅ Alerte acquittée pour la sonde {sonde} par commande Telegram." - else: - message = f"ℹ️ Aucune alerte active à acquitter pour la sonde {sonde}." - - url = f"https://api.telegram.org/bot{token}/sendMessage" - try: - requests.get(url, params={'chat_id': chat_id, 'text': message}) - except Exception as e: - print(f"[ERREUR] envoi message Telegram : {e}") - -def send_telegram_message(sonde, temperature): - token = "5714323406:AAGSj9jrfBHbfxubz3ooabPEizI8aBOLnvE" - chat_id = "-1002442631825" - message = f"⚠️ Alerte température : La sonde {sonde} dépasse la limite avec une température de {temperature}°C." - url = f"https://api.telegram.org/bot{token}/sendMessage" - params = {'chat_id': chat_id, 'text': message} - try: - response = requests.get(url, params=params) - if response.status_code == 200: - print(f"Message envoyé via Telegram pour la sonde {sonde}.") - else: - print(f"Erreur lors de l'envoi du message Telegram : {response.status_code}") - except Exception as e: - print(f"Erreur lors de l'envoi du message Telegram : {e}") - - -def get_chat_id(cursor, site): - cursor.execute("SELECT Chat_ID FROM Sites WHERE Nom = %s;", (site,)) - result = cursor.fetchone() - if result: - return result[0] - else: - print(f"Aucun Chat_ID trouvé pour le site {site}") - return None - -def passer_en_maintenance(cursor, site, sonde, chat_id, token): - try: - query = """ - UPDATE Chambres_froides - SET Etat = 'Off' - WHERE Lieu = %s AND Sonde = %s; - """ - cursor.execute(query, (site, sonde)) - lignes_modifiees = cursor.rowcount - - if lignes_modifiees > 0: - message = f"🛠️ La sonde {sonde} a été passée en mode maintenance (OFF)." - else: - message = f"⚠️ Sonde {sonde} introuvable pour le site {site}." - - url = f"https://api.telegram.org/bot{token}/sendMessage" - requests.get(url, params={'chat_id': chat_id, 'text': message}) - - except Exception as e: - print(f"[ERREUR] lors du passage en maintenance : {e}") - -def reactiver_sonde(cursor, site, sonde, chat_id, token): - try: - query = """ - UPDATE Chambres_froides - SET Etat = 'On' - WHERE Lieu = %s AND Sonde = %s; - """ - cursor.execute(query, (site, sonde)) - lignes_modifiees = cursor.rowcount - - if lignes_modifiees > 0: - message = f"✅ La sonde {sonde} a été réactivée (ON)." - else: - message = f"⚠️ Sonde {sonde} introuvable pour le site {site}." - - url = f"https://api.telegram.org/bot{token}/sendMessage" - requests.get(url, params={'chat_id': chat_id, 'text': message}) - - except Exception as e: - print(f"[ERREUR] lors de la réactivation : {e}") - -def etat_sondes(cursor, site, chat_id, token): - query = "SELECT Sonde, Etat FROM Chambres_froides WHERE Lieu = %s ORDER BY Sonde;" - cursor.execute(query, (site,)) - result = cursor.fetchall() - - message = f"📊 État des sondes - {site} :\n" - for sonde, etat in result: - symbole = "🟢" if etat.upper() == "ON" else "🔴" - message += f"{symbole} {sonde} ({etat.upper()})\n" - - url = f"https://api.telegram.org/bot{token}/sendMessage" - requests.get(url, params={'chat_id': chat_id, 'text': message}) - -def monitor_temperatures_simple(site, db, cursor): - table_historique = site - table_alertes = f"Alertes_{site}" - sondes = get_active_sondes(cursor, site) - print(f"[MONITORING] Sondes actives pour {site} : {sondes}") - - for sonde, limite in sondes.items(): - alert_needed, temperature = check_temperature_limits(cursor, table_historique, sonde, limite) - if alert_needed: - create_alert(db, cursor, table_alertes, sonde, temperature) - else: - resolve_alert(cursor, table_alertes, sonde) - - db.commit() - print("[MONITORING] Vérification des sondes terminée.") - -def monitor_temperatures(site): - db = connect_db() - cursor = db.cursor() - - table_historique = site # Ex: Saclay - table_alertes = f"Alertes_{site}" # Ex: Alertes_Saclay - - sondes = get_active_sondes(cursor, site) - print(f"Sondes actives pour le site {site} :", sondes) - - for sonde, limite in sondes.items(): - alert_needed, temperature = check_temperature_limits(cursor, table_historique, sonde, limite) - if alert_needed: - create_alert(db, cursor, table_alertes, sonde, temperature) - else: - resolve_alert(cursor, table_alertes, sonde) - - db.commit() - listen_for_commands(db, cursor, site) - cursor.close() - db.close() - -def listen_for_commands(db, cursor, site): - token = "5714323406:AAGSj9jrfBHbfxubz3ooabPEizI8aBOLnvE" - chat_id = get_chat_id(cursor, site) - offset_file = os.path.join(os.path.dirname(__file__), f"last_update_id_{site}.txt") - - try: - with open(offset_file, 'r') as f: - last_update_id = int(f.read().strip()) - except FileNotFoundError: - last_update_id = None - - url = f"https://api.telegram.org/bot{token}/getUpdates" - if last_update_id is not None: - url += f"?offset={last_update_id + 1}" - - try: - response = requests.get(url) - data = response.json() - - if "result" in data: - for update in data["result"]: - update_id = update["update_id"] - - if "message" in update: - message = update["message"]["text"] - print(f"[CMD] Message reçu : {message}") - - if message.lower().startswith("/etat"): - etat_sondes(cursor, site, chat_id, token) - - elif message.lower().startswith("/acquitter"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - acquitter_alerte(cursor, site, sonde, chat_id, token) - db.commit() - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /acquitter " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - elif message.lower().startswith("/maintenance"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - passer_en_maintenance(cursor, site, sonde, chat_id, token) - db.commit() - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /maintenance " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - elif message.lower().startswith("/reactiver"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - reactiver_sonde(cursor, site, sonde, chat_id, token) - db.commit() - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /reactiver " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - elif message.lower().startswith("/test"): - parts = message.strip().split(" ", 1) - if len(parts) == 2 and parts[1].strip(): - sonde = parts[1].strip() - simulate_alert(db, cursor, site, sonde, chat_id, token) - else: - erreur_msg = "❌ Utilisation incorrecte. Format attendu : /test " - requests.get(f"https://api.telegram.org/bot{token}/sendMessage", - params={'chat_id': chat_id, 'text': erreur_msg}) - - with open(offset_file, 'w') as f: - f.write(str(update_id)) - - except Exception as e: - print(f"Erreur lors de la lecture des commandes Telegram : {e}") - - -def main(): - site = sys.argv[1] if len(sys.argv) > 1 else "Saclay" - db = connect_db() - cursor = db.cursor() - - # ✅ Planification : tous les jours à 07:00 → état des sondes - schedule.every().day.at("07:00").do(envoi_etat_quotidien, cursor=cursor, site=site) - - # ✅ Planification : toutes les 2m30 → surveillance - schedule.every(2).minutes.do(monitor_temperatures_simple, site=site, db=db, cursor=cursor) - - try: - while True: - schedule.run_pending() - listen_for_commands(db, cursor, site) - time.sleep(2) # petite pause pour ne pas surcharger Telegram - finally: - cursor.close() - db.close() - -if __name__ == "__main__": - main() diff --git a/Test_mail.py b/Test_mail.py deleted file mode 100644 index b0183c7..0000000 --- a/Test_mail.py +++ /dev/null @@ -1,23 +0,0 @@ -import smtplib -from email.mime.text import MIMEText - -def envoyer_mail(sujet, message, destinataires): - msg = MIMEText(message) - msg['Subject'] = sujet - msg['From'] = 'alertes_saclay@domo91.fr' - msg['To'] = ', '.join(destinataires) - - try: - with smtplib.SMTP_SSL('smtp.mail.ovh.net', 465) as server: - server.login('alertes_saclay@domo91.fr', 'Kdpke674y23Feq^H') - server.sendmail(msg['From'], destinataires, msg.as_string()) - print(f"📧 Mail envoyé à {destinataires}") - except Exception as e: - print(f"Erreur envoi mail : {e}") - -# --- Test d'envoi --- -envoyer_mail( - sujet="🧪 Test d'envoi d'alerte", - message="Ceci est un test de l'envoi d'e-mail via alertes_saclay@domo91.fr.", - destinataires=["services@domo91.fr"] -) diff --git a/Tracker.py b/Tracker.py deleted file mode 100644 index b35cecb..0000000 --- a/Tracker.py +++ /dev/null @@ -1,106 +0,0 @@ -import paho.mqtt.client as mqtt -import mysql.connector -import re # Import de la bibliothèque des expressions régulières - - -# Configuration de la base de données MySQL -db_config = { - 'user': 'superviseur', # Remplacez par votre utilisateur MySQL - 'password': 'Bto7Lm_z]m!BFH!*', # Remplacez par votre mot de passe MySQL - 'host': '54.36.188.119', # Adresse de votre serveur MySQL (localhost si en local) - 'database': 'Sondes' # Nom de la base de données MySQL -} - - -def convertir_rom_id_en_hexa(rom_id): - # On découpe la chaîne rom_id en paires de deux caractères - hex_parts = [f"0x{rom_id[i:i + 2]}" for i in range(0, len(rom_id), 2)] - return ",".join(hex_parts) - - -# Connexion à la base de données MySQL -def connect_db(): - return mysql.connector.connect(**db_config) - - -# Fonction pour vérifier si la sonde est déjà présente dans la base -def sonde_deja_presente(rom_id): - conn = connect_db() - cursor = conn.cursor() - try: - # Vérifier si la sonde existe déjà dans la base - cursor.execute("SELECT COUNT(*) FROM Tracker WHERE rom_id = %s", (rom_id,)) - result = cursor.fetchone() - return result[0] > 0 # Si le nombre est supérieur à 0, la sonde est déjà présente - - except mysql.connector.Error as err: - print(f"Erreur MySQL lors de la vérification de la sonde : {err}") - return False - - finally: - cursor.close() - conn.close() - - -# Fonction pour insérer les sondes dans la base de données -def inserer_sonde(rom_id): - if sonde_deja_presente(rom_id): - print(f"Sonde {rom_id} déjà présente dans la base de données. Aucune insertion effectuée.") - return - - conn = connect_db() - cursor = conn.cursor() - try: - # Conversion en hexadécimal - rom_id_hexa = convertir_rom_id_en_hexa(rom_id) - - # Insertion de rom_id et de sa version hexa dans la base - cursor.execute("INSERT INTO Tracker (rom_id, hexa) VALUES (%s, %s)", (rom_id, rom_id_hexa)) - conn.commit() - print(f"Sonde {rom_id} insérée dans la base de données avec son format hexa {rom_id_hexa}.") - - except mysql.connector.Error as err: - print(f"Erreur MySQL : {err}") - - finally: - cursor.close() - conn.close() - - -# Fonction de callback pour gérer les messages MQTT -def on_message(_client, _userdata, message): - payload = message.payload.decode() - print(f"Message reçu : {payload}") - - # Utilisation de re pour extraire les ROM IDs (Sonde [rom_id]) - rom_ids = re.findall(r"[0-9a-fA-F]{16}", payload) # Capturer les IDs de 16 caractères - if rom_ids: - for rom_id in rom_ids: - inserer_sonde(rom_id) - else: - print("Aucun ROM ID trouvé dans le message.") - - -# Configuration du client MQTT -mqtt_broker = "46.105.92.116" -mqtt_port = 1883 # Vérifiez si votre broker utilise un autre port -mqtt_user = "Bwps" -mqtt_password = "scJ5ACj2keRfI^" -mqtt_topic = "Tracker/sondes" - -client = mqtt.Client() - -# Authentification MQTT -client.username_pw_set(mqtt_user, mqtt_password) - -# Configuration du callback pour les messages MQTT -client.on_message = on_message - -# Connexion au broker MQTT -client.connect(mqtt_broker, mqtt_port, 60) - -# Souscription au topic Tracker/sondes -client.subscribe(mqtt_topic) - -# Démarrer la boucle MQTT -client.loop_forever() diff --git a/check_supervisor.py b/check_supervisor.py deleted file mode 100644 index fdbdb7a..0000000 --- a/check_supervisor.py +++ /dev/null @@ -1,56 +0,0 @@ -import subprocess -import smtplib -from email.mime.text import MIMEText - -def envoyer_mail(sujet, message, destinataires): - msg = MIMEText(message) - msg['Subject'] = sujet - msg['From'] = 'alertes_saclay@domo91.fr' - msg['To'] = ', '.join(destinataires) - - try: - with smtplib.SMTP_SSL('smtp.mail.ovh.net', 465) as server: - server.login('alertes_saclay@domo91.fr', 'Kdpke674y23Feq^H') - server.sendmail(msg['From'], destinataires, msg.as_string()) - print(f"📧 Mail envoyé à {destinataires}") - except Exception as e: - print(f"Erreur envoi mail : {e}") - -# Liste des processus attendus -processus_attendus = [ - "Chauffage", - "Cuisine_Saclay", - "Monitor", - "Streamlit", - "Telegram_sondes", - "cuisine_meudon" -] - -# Commande supervisor -output = subprocess.getoutput("supervisorctl status") - -# Vérification -anomalies = [] -for line in output.splitlines(): - for process in processus_attendus: - if line.startswith(process) and "RUNNING" not in line: - anomalies.append(line) - -# Logs (facultatif) -with open("/var/log/supervisor_alert.log", "a") as log: - if anomalies: - log.write("🚨 Anomalies détectées :\n") - for a in anomalies: - log.write(f"{a}\n") - else: - log.write("✅ Tous les processus sont OK.\n") - -# Envoi de mail si nécessaire -if anomalies: - message = "\n".join(anomalies) - envoyer_mail( - sujet="🚨 Alerte Supervisor : processus en erreur", - message=message, - destinataires=["services@domo91.fr"] - ) - diff --git a/deploy.sh.py b/deploy.sh.py deleted file mode 100644 index 1882366..0000000 --- a/deploy.sh.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -echo "🔄 Déploiement depuis Gitea - branche main" - -cd /home/debian/travail/Gestion_sondes || exit 1 - -# Récupération des dernières modifs -git fetch origin -git checkout main -git pull origin main - -# Sécurisation en lecture seule (facultatif mais recommandé) -chmod 444 Monitor.py Cuisine_*.py Streamlit.py - -# Redémarrage de Supervisor -echo "🔁 Redémarrage des services Supervisor..." -sudo supervisorctl restart all - -echo "✅ Déploiement terminé avec succès" \ No newline at end of file diff --git a/logs_analyse.py b/logs_analyse.py deleted file mode 100644 index 5630e30..0000000 --- a/logs_analyse.py +++ /dev/null @@ -1,39 +0,0 @@ -import streamlit as st -import pandas as pd -import matplotlib.pyplot as plt - -# --- Chargement des données --- -try: - df = pd.read_csv("/home/debian/travail/logs_monitor.csv", sep=";", parse_dates=["Date"]) -except FileNotFoundError: - st.error("📂 Le fichier de log n'a pas été trouvé.") - st.stop() - -st.title("🧾 Analyse des scans Monitor.py") - -# --- Filtres --- -df["Date_str"] = df["Date"].dt.date -dates_dispo = sorted(df["Date_str"].unique(), reverse=True) -date_selection = st.selectbox("📅 Sélectionnez une date :", dates_dispo) - -lieux = sorted(df["Lieu"].unique()) -lieu_selection = st.selectbox("📍 Site :", lieux) - -df_filtré = df[(df["Date_str"] == date_selection) & (df["Lieu"] == lieu_selection)] - -sondes = sorted(df_filtré["Sonde"].unique()) -sonde_selection = st.selectbox("🧪 Sonde :", sondes) - -df_sonde = df_filtré[df_filtré["Sonde"] == sonde_selection] - -# --- Graphique température --- -fig, ax = plt.subplots(figsize=(10, 4)) -ax.plot(df_sonde["Date"], df_sonde["Température"], marker='o') -ax.set_title(f"Évolution de la température - {sonde_selection}") -ax.set_xlabel("Heure") -ax.set_ylabel("Température (°C)") -st.pyplot(fig) - -# --- Tableau complet du jour/sonde sélectionnés --- -st.markdown("### 📋 Détail des scans") -st.dataframe(df_sonde[["Date", "Sonde", "Température", "Seuil", "État"]], use_container_width=True) diff --git a/rapport_supervisor.py b/rapport_supervisor.py deleted file mode 100644 index 6fc3642..0000000 --- a/rapport_supervisor.py +++ /dev/null @@ -1,47 +0,0 @@ -import subprocess -import smtplib -from email.mime.text import MIMEText -from datetime import datetime - -# Informations mail -FROM = "alertes_saclay@domo91.fr" -TO = ["services@domo91.fr"] -SUBJECT = f"🟢 Rapport quotidien - Supervisor OK ({datetime.now().strftime('%d/%m/%Y')})" - -# Liste des services attendus -processus_attendus = [ - "Chauffage", - "Cuisine_Saclay", - "Monitor", - "Streamlit", - "Telegram_sondes", - "cuisine_meudon" -] - -# Vérifie les statuts -output = subprocess.getoutput("supervisorctl status") -etat = "\n".join(line for line in output.splitlines() if any(p in line for p in processus_attendus)) - -# Contenu du mail -message = f"""Bonjour, - -Voici l'état des processus supervisés ce jour ({datetime.now().strftime('%Y-%m-%d %H:%M')}). - -{etat} - -Cordialement, -Domo91 -""" - -msg = MIMEText(message) -msg["Subject"] = SUBJECT -msg["From"] = FROM -msg["To"] = ", ".join(TO) - -try: - with smtplib.SMTP_SSL("smtp.mail.ovh.net", 465) as server: - server.login(FROM, "Kdpke674y23Feq^H") - server.sendmail(FROM, TO, msg.as_string()) - print("✅ Rapport envoyé avec succès.") -except Exception as e: - print(f"Erreur envoi mail : {e}")