Remise en état des relevés temp
This commit is contained in:
166
app/Mqtt_saclay.py
Normal file
166
app/Mqtt_saclay.py
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Mqtt_saclay.py
|
||||
Récupère les mesures MQTT du site Saclay et les insère dans la table Sondes.Saclay.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
import mysql.connector
|
||||
from mysql.connector import Error
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
from paho.mqtt.client import CallbackAPIVersion
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# =========================
|
||||
# Chargement du .env
|
||||
# =========================
|
||||
load_dotenv()
|
||||
|
||||
DB_HOST = os.getenv("DB_HOST")
|
||||
DB_USER = os.getenv("DB_USER")
|
||||
DB_PASS = os.getenv("DB_PASS")
|
||||
DB_NAME = os.getenv("DB_NAME")
|
||||
|
||||
MQTT_HOST = os.getenv("MQTT_HOST")
|
||||
MQTT_USER = os.getenv("MQTT_USER")
|
||||
MQTT_PASS = os.getenv("MQTT_PASS")
|
||||
MQTT_PORT = int(os.getenv("MQTT_PORT", 1883))
|
||||
|
||||
GYRO_TOPIC_SACLAY = os.getenv("GYRO_MQTT_TOPIC_SACLAY", "Saclay/gyrophare")
|
||||
TABLE_NAME = "Saclay"
|
||||
|
||||
# =========================
|
||||
# Logging
|
||||
# =========================
|
||||
def setup_logging():
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
formatter = logging.Formatter(
|
||||
"%(asctime)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
|
||||
# Console
|
||||
console = logging.StreamHandler()
|
||||
console.setFormatter(formatter)
|
||||
logger.addHandler(console)
|
||||
|
||||
# Logs fichier
|
||||
log_dir = os.getenv("LOG_DIR", "./Logs")
|
||||
try:
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
file_handler = RotatingFileHandler(
|
||||
os.path.join(log_dir, "Mqtt_saclay.log"),
|
||||
maxBytes=1_000_000,
|
||||
backupCount=5,
|
||||
encoding="utf-8",
|
||||
)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
except Exception as e:
|
||||
logging.warning("Impossible de créer le fichier de log : %s", e)
|
||||
|
||||
|
||||
# =========================
|
||||
# Accès MySQL
|
||||
# =========================
|
||||
def insert_temperature(sonde: str, temperature: float) -> None:
|
||||
try:
|
||||
conn = mysql.connector.connect(
|
||||
host=DB_HOST,
|
||||
user=DB_USER,
|
||||
password=DB_PASS,
|
||||
database=DB_NAME,
|
||||
)
|
||||
|
||||
cursor = conn.cursor()
|
||||
sql = f"INSERT INTO {TABLE_NAME} (Sonde, Temperature) VALUES (%s, %s)"
|
||||
cursor.execute(sql, (sonde, temperature))
|
||||
conn.commit()
|
||||
|
||||
logging.info("Insertion OK -> %s = %.2f", sonde, temperature)
|
||||
|
||||
except Error as e:
|
||||
logging.exception("Erreur MySQL pour la sonde %s : %s", sonde, e)
|
||||
|
||||
finally:
|
||||
try:
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if conn and conn.is_connected():
|
||||
conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
# =========================
|
||||
# Callbacks MQTT (API v2)
|
||||
# =========================
|
||||
def on_connect(client, userdata, flags, reason_code, properties=None):
|
||||
if reason_code == 0:
|
||||
logging.info("Connecté au broker MQTT (%s)", MQTT_HOST)
|
||||
client.subscribe("Saclay/#")
|
||||
logging.info("Abonné au topic : Saclay/#")
|
||||
else:
|
||||
logging.error("Échec de connexion MQTT, code retour = %s", reason_code)
|
||||
|
||||
|
||||
def on_message(client, userdata, msg: mqtt.MQTTMessage):
|
||||
topic = msg.topic
|
||||
payload_raw = msg.payload.decode("utf-8", errors="ignore").strip()
|
||||
|
||||
logging.debug("Msg reçu : topic=%s payload=%s", topic, payload_raw)
|
||||
|
||||
if topic == GYRO_TOPIC_SACLAY:
|
||||
return # on ignore le gyrophare
|
||||
|
||||
sonde = topic.split("/")[-1] if "/" in topic else topic
|
||||
|
||||
try:
|
||||
value = float(payload_raw.replace(",", "."))
|
||||
except ValueError:
|
||||
logging.warning("Payload non numérique (topic=%s payload=%s)", topic, payload_raw)
|
||||
return
|
||||
|
||||
insert_temperature(sonde, value)
|
||||
|
||||
|
||||
# =========================
|
||||
# Programme principal
|
||||
# =========================
|
||||
def main():
|
||||
setup_logging()
|
||||
logging.info("Démarrage du script Mqtt_saclay")
|
||||
|
||||
client = mqtt.Client(
|
||||
client_id="Mqtt_saclay_client",
|
||||
callback_api_version=CallbackAPIVersion.VERSION2
|
||||
)
|
||||
client.username_pw_set(MQTT_USER, MQTT_PASS)
|
||||
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
|
||||
try:
|
||||
client.connect(MQTT_HOST, MQTT_PORT, keepalive=60)
|
||||
except Exception as e:
|
||||
logging.exception("Impossible de se connecter au broker MQTT : %s", e)
|
||||
return
|
||||
|
||||
logging.info("Boucle MQTT en cours (Ctrl+C pour arrêter)...")
|
||||
try:
|
||||
client.loop_forever()
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Arrêt demandé par l'utilisateur.")
|
||||
finally:
|
||||
client.disconnect()
|
||||
logging.info("Déconnexion MQTT.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user