Nettoyage de la branche product : suppression des fichiers de develop

This commit is contained in:
2025-04-17 14:07:18 +02:00
parent 187d4a1650
commit 8f7fda61b4
14 changed files with 244 additions and 464 deletions

21
.idea/workspace.xml generated
View File

@@ -4,8 +4,10 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="a12d9762-568e-4ace-91c1-148c598387a7" name="Changes" comment="&quot;Injection données dans Tables Meudon et Roissy&quot;">
<change beforePath="$PROJECT_DIR$/.idea/.name" beforeDir="false" />
<list default="true" id="a12d9762-568e-4ace-91c1-148c598387a7" name="Changes" comment="&quot;Ajout bt impression rapports et dossier PDF crée&quot;">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Chat-Id.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Chaufferie.py" beforeDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -86,7 +88,7 @@
"Python.test.executor": "Run",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"git-widget-placeholder": "develop",
"git-widget-placeholder": "product",
"ignore.virus.scanning.warn.message": "true",
"last_opened_file_path": "C:/Users/miche/PycharmProjects/Gestion sondes",
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
@@ -246,7 +248,15 @@
<option name="project" value="LOCAL" />
<updated>1744519840546</updated>
</task>
<option name="localTasksCounter" value="13" />
<task id="LOCAL-00013" summary="&quot;Ajout bt impression rapports et dossier PDF crée&quot;">
<option name="closed" value="true" />
<created>1744891048964</created>
<option name="number" value="00013" />
<option name="presentableId" value="LOCAL-00013" />
<option name="project" value="LOCAL" />
<updated>1744891048964</updated>
</task>
<option name="localTasksCounter" value="14" />
<servers />
</component>
<component name="VcsManagerConfiguration">
@@ -255,6 +265,7 @@
<MESSAGE value="Streamlit.py" />
<MESSAGE value="Base de données SG" />
<MESSAGE value="&quot;Injection données dans Tables Meudon et Roissy&quot;" />
<option name="LAST_COMMIT_MESSAGE" value="&quot;Injection données dans Tables Meudon et Roissy&quot;" />
<MESSAGE value="&quot;Ajout bt impression rapports et dossier PDF crée&quot;" />
<option name="LAST_COMMIT_MESSAGE" value="&quot;Ajout bt impression rapports et dossier PDF crée&quot;" />
</component>
</project>

29
Backup/.deploy.sh Normal file
View File

@@ -0,0 +1,29 @@
#!/bin/bash
LOG="/home/debian/travail/Logs/deploy.log"
REPO_PATH="/home/debian/travail/Gestion_sondes"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] 🔄 Déploiement en cours depuis Gitea (branche product)..." >> $LOG
cd $REPO_PATH
# S'assurer d'être sur la bonne branche
git checkout product >> $LOG 2>&1
git pull origin product >> $LOG 2>&1
# Redémarrer les services Supervisor
for service in Cuisine_Saclay Monitor cuisine_meudon domo91
do
supervisorctl stop $service >> $LOG 2>&1
done
sleep 2
for service in Cuisine_Saclay Monitor cuisine_meudon domo91
do
supervisorctl start $service >> $LOG 2>&1
done
DATE_END=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE_END] ✅ Déploiement terminé avec succès (branche product)" >> $LOG

View File

@@ -0,0 +1,184 @@
# Application Gestion de sondes
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
import random
from fpdf import FPDF
import os
st.set_page_config(page_title="Domo91 - Surveillance", layout="wide")
st.title("📡 Supervision Températures")
# --- Configuration base de données ---
db_config = {
"host": "54.36.188.119",
"user": "michel",
"password": "#SO2&1nf%mZ@jfh",
"database": "Sondes"
}
# --- 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
# --- Sidebar (connexion + bouton PDF) ---
with st.sidebar:
st.header("🔐 Connexion")
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"):
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()
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)
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())
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"),)
)
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]
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.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))
ax.plot(df_filtré["Date"], df_filtré["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.")
cursor.close()
conn.close()
except Exception as e:
st.error(f"Erreur MySQL : {e}")

6
Backup/backup_mysql.sh Normal file
View File

@@ -0,0 +1,6 @@
# Fichier de sauvegarde BDD sur Syno en NFS
# Fichier my.cnf
#[mysqldump]
#user=root
#password=4V5t9P!Z2HgT#CLFes4cntEeNBWs
mysqldump --defaults-file=/home/debian/travail/my.cnf -u root --all-databases > /mnt/syno920/all-$(date +%Y%m%d).sql

9
Backup/requirements.txt Normal file
View File

@@ -0,0 +1,9 @@
mysql~=0.0.3
mysql-connector-python~=9.2.0
pandas~=2.2.3
DateTime~=5.5
streamlit~=1.44.1
matplotlib~=3.10.1
paho-mqtt~=2.1.0
requests~=2.32.3
schedule~=1.2.2

View File

@@ -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}")

View File

@@ -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

View File

@@ -1,18 +0,0 @@
# Purge de la table Sondes.Alertes_Saclay.
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.")

View File

@@ -1,52 +0,0 @@
# 🌡️ Gestion des sondes domotiques
[![Version Python](https://img.shields.io/badge/Python-3.10-blue)](https://python.org)
[![Licence](https://img.shields.io/badge/Licence-Propriétaire-orange)](https://mj91.fr:448/michel/Gestion_sondes)
[![Gitea](https://img.shields.io/badge/Gitea-auto--hébergé-green)](https://mj91.fr:448)
Application de **surveillance des températures** avec alertes, visualisation Streamlit, et déploiement automatisé via Gitea + Supervisor.
---
## 🧩 Fonctionnalités principales
- 🔍 Lecture de capteurs **DS18B20** et **DHT22**
- 📨 Transmission via **MQTT**
- 📊 Interface **Streamlit** (app.domo91.fr)
- 🔔 Alertes **email / Telegram** si dépassement > 30 minutes
- 🧠 Déploiement auto avec **`deploy.sh`**
- 🧾 Stockage SQL sur **MySQL (VPS)**
---
## 📊 Exemple de visualisation
Voici un aperçu dun graphique dans linterface Streamlit :
![Exemple de graphique Streamlit](https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Matplotlib_figure.svg/800px-Matplotlib_figure.svg.png)
---
## 🗂️ Structure du projet
| Fichier | Description |
|-----------------------------|---------------------------------------------------------------------|
| `Monitor.py` | Analyse de température et alertes |
| `Streamlit.py` | Interface graphique web |
| `Cuisine_saclay.py` | Script capteur pour le site de Saclay |
| `Cuisine_meudon.py` | Script capteur pour Meudon |
| `check_supervisor.py` | Vérifie létat des scripts supervisés |
| `deploy.sh` | Déploiement auto depuis Gitea (branche `product`) |
| `requirements.txt` | Dépendances Python |
---
## 🧪 Installation locale
```bash
git clone https://mj91.fr:448/michel/Gestion_sondes.git
cd Gestion_sondes
python -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
pip install -r requirements.txt

View File

@@ -1,107 +0,0 @@
# Insertion de données da l'app SG.
import streamlit as st
import mysql.connector
from dotenv import load_dotenv
import os
from datetime import datetime
load_dotenv()
st.set_page_config(page_title="Insertion Mysql", layout="centered")
st.title("🗓️ Insertion dans une base MySQL")
# Charger les identifiants
DB_HOST = os.getenv("DB_HOST")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
# Connexion sans DB initiale pour lister les bases
@st.cache_data
def get_databases():
conn = mysql.connector.connect(
host=DB_HOST,
user=DB_USER,
password=DB_PASSWORD
)
cursor = conn.cursor()
cursor.execute("SHOW DATABASES")
bases = [db[0] for db in cursor.fetchall()]
conn.close()
return bases
# Connexion avec DB sélectionnée
def connect_to_db(db_name):
return mysql.connector.connect(
host=DB_HOST,
user=DB_USER,
password=DB_PASSWORD,
database=db_name
)
# --- Interface principale ---
base = st.selectbox("Choisir une base de données", get_databases())
if base:
conn = connect_to_db(base)
cursor = conn.cursor()
cursor.execute("SHOW TABLES")
tables = [table[0] for table in cursor.fetchall()]
table = st.selectbox("Choisir une table", tables)
if table:
cursor.execute(f"DESCRIBE {table}")
colonnes = cursor.fetchall()
# Détection clé primaire
cursor.execute(f"SHOW INDEX FROM {table} WHERE Key_name = 'PRIMARY'")
pk = cursor.fetchone()
primary_key = pk[4] if pk else None
champ_date_candidates = [col[0] for col in colonnes if "date" in col[1].lower()]
champ_date = st.selectbox("Champ de date", champ_date_candidates)
nb_mois = st.number_input("Nombre d'insertions mensuelles", 1, 36, 6)
date_depart = st.date_input("Date de départ des insertions", value=datetime.today().date())
st.subheader("Champs à insérer (hors clé primaire et champ de date)")
champs_choisis = []
champs_editables = [col for col in colonnes if col[0] != primary_key and col[0] != champ_date]
for col in champs_editables:
if st.checkbox(f"{col[0]} ({col[1]})", value=True):
champs_choisis.append(col[0])
with st.form("formulaire_insertion"):
st.markdown("**Valeurs fixes pour les champs cochés**")
valeurs_fixes = {}
for nom in champs_choisis:
val = st.text_input(nom)
valeurs_fixes[nom] = val if val != "" else None
submit = st.form_submit_button("Insérer")
try:
cursor = conn.cursor()
insert_count = 0
for i in range(nb_mois):
year = date_depart.year + (date_depart.month + i - 1) // 12
month = (date_depart.month + i - 1) % 12 + 1
day = min(date_depart.day, 28)
date_cible = datetime(year, month, day).date()
champs = [champ_date] + list(valeurs_fixes.keys())
valeurs = [date_cible] + list(valeurs_fixes.values())
sql = f"INSERT INTO {table} ({', '.join(champs)}) VALUES ({', '.join(['%s'] * len(valeurs))})"
cursor.execute(sql, valeurs)
insert_count += 1
conn.commit()
st.success(f"{insert_count} lignes insérées avec succès dans `{table}`.")
except Exception as e:
st.error(f"❌ Erreur lors de linsertion : {e}")
conn.commit()
st.success(f"{insert_count} lignes insérées avec succès dans `{table}`.")
st.success(f"{insert_count} lignes insérées avec succès.")

View File

@@ -1,24 +0,0 @@
# Programme de test de la BAL alertes_saclay@domo91.fr.
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"]
)

View File

@@ -1,106 +0,0 @@
# Programme de récupération des adresses de sondes DS18B20 et envoie dans table Sondes.Tracker.
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()

View File

@@ -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)

View File

@@ -1,47 +0,0 @@
# Controle des services supervisor envoi en cas de disfonction et tous les jours à sept heures
# a faire tourner avec crontb -e en sudo
# */30 * * * * /home/debian/travail/myenv/bin/python3 /home/debian/travail/Scripts/supervisor_watchdog.py
import subprocess
import smtplib
from email.mime.text import MIMEText
from datetime import datetime
heure_actuelle = datetime.now().strftime("%H:%M")
etat_services = []
anomalies = []
try:
output = subprocess.check_output("/usr/bin/supervisorctl status", shell=True, text=True)
for line in output.splitlines():
parts = line.split()
if len(parts) >= 2:
nom, statut = parts[0], parts[1]
etat_services.append(f"{nom}{statut}")
if statut != "RUNNING":
anomalies.append(f"{nom}{statut}")
except Exception as e:
etat_services.append("❌ Impossible d'exécuter supervisorctl")
anomalies.append(f"Erreur : {e}")
# Déclenchement mail si anomalie ou à 07:00
envoyer_mail = bool(anomalies) or heure_actuelle == "07:00"
if envoyer_mail:
sujet = "⚠️ Alerte Supervisor" if anomalies else "✅ Rapport quotidien Supervisor"
intro = "🛑 Les services suivants ne sont pas en RUNNING :" if anomalies else "✅ Tous les services supervisés sont en RUNNING."
contenu = f"{intro}\n\n" + "\n".join(etat_services)
msg = MIMEText(contenu)
msg["Subject"] = sujet
msg["From"] = "alertes_saclay@domo91.fr"
msg["To"] = "services@domo91.fr"
try:
with smtplib.SMTP_SSL("smtp.mail.ovh.net", 465) as server:
server.login("alertes_saclay@domo91.fr", "Kdpke674y23Feq^H")
server.sendmail(msg["From"], [msg["To"]], msg.as_string())
print("📧 Mail envoyé.")
except Exception as e:
print(f"Erreur envoi mail : {e}")
else:
print("🕖 Aucun mail envoyé (tout est OK et ce nest pas lheure du rapport).")