2026-05-07 00:13:17 +02:00
|
|
|
import paho.mqtt.client as mqtt
|
2026-05-09 15:36:31 +02:00
|
|
|
import psycopg2
|
2026-05-07 00:13:17 +02:00
|
|
|
import logging
|
|
|
|
|
import sys
|
2026-05-09 15:36:31 +02:00
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
MQTT_HOST = os.getenv("MQTT_HOST", "mosquitto")
|
|
|
|
|
MQTT_PORT = int(os.getenv("MQTT_PORT", 1883))
|
|
|
|
|
PG_DSN = os.getenv("DATABASE_URL", "postgresql://simugaz:simugaz@db/simugaz")
|
2026-05-07 00:13:17 +02:00
|
|
|
|
|
|
|
|
logging.basicConfig(
|
|
|
|
|
level=logging.INFO,
|
|
|
|
|
format="%(asctime)s [%(levelname)s] %(message)s",
|
|
|
|
|
datefmt="%Y-%m-%dT%H:%M:%S",
|
2026-05-09 15:36:31 +02:00
|
|
|
stream=sys.stdout,
|
|
|
|
|
force=True,
|
2026-05-07 00:13:17 +02:00
|
|
|
)
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
2026-05-09 15:36:31 +02:00
|
|
|
def get_db():
|
|
|
|
|
for _ in range(10):
|
|
|
|
|
try:
|
|
|
|
|
conn = psycopg2.connect(PG_DSN)
|
|
|
|
|
conn.autocommit = True
|
|
|
|
|
log.info("PostgreSQL connecté")
|
|
|
|
|
return conn
|
|
|
|
|
except Exception as e:
|
|
|
|
|
log.warning(f"Attente PostgreSQL... ({e})")
|
|
|
|
|
time.sleep(3)
|
|
|
|
|
raise RuntimeError("Impossible de se connecter à PostgreSQL")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_device_id(conn, dev_eui: str) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Insère le device si inconnu
|
|
|
|
|
Retourne le device_id correspondant au dev_eui
|
|
|
|
|
"""
|
|
|
|
|
with conn.cursor() as cur:
|
|
|
|
|
cur.execute(
|
|
|
|
|
"""
|
|
|
|
|
INSERT INTO device (device_eui)
|
|
|
|
|
VALUES (%s)
|
|
|
|
|
ON CONFLICT (device_eui) DO NOTHING
|
|
|
|
|
""",
|
|
|
|
|
(dev_eui,),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
cur.execute("SELECT device_id FROM device WHERE device_eui = %s", (dev_eui,))
|
|
|
|
|
row = cur.fetchone()
|
|
|
|
|
return str(row[0])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def insert_reading(conn, device_id: str, pulses: int):
|
|
|
|
|
"""Insère une télérelève liée au device"""
|
|
|
|
|
with conn.cursor() as cur:
|
|
|
|
|
cur.execute(
|
|
|
|
|
"""
|
|
|
|
|
INSERT INTO reading (device_id, date, pulses)
|
|
|
|
|
VALUES (%s, NOW(), %s)
|
|
|
|
|
""",
|
|
|
|
|
(device_id, pulses),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db_conn = None
|
|
|
|
|
|
|
|
|
|
|
2026-05-07 00:13:17 +02:00
|
|
|
def on_connect(client, userdata, flags, reason_code, properties):
|
2026-05-09 15:36:31 +02:00
|
|
|
log.info(f"MQTT connecté (code={reason_code})")
|
|
|
|
|
client.subscribe("application/+/device/+/event/up", qos=1)
|
|
|
|
|
|
2026-05-07 00:13:17 +02:00
|
|
|
|
|
|
|
|
def on_message(client, userdata, msg):
|
2026-05-09 15:36:31 +02:00
|
|
|
try:
|
|
|
|
|
body = json.loads(msg.payload)
|
|
|
|
|
dev_eui = body["deviceInfo"]["devEui"]
|
|
|
|
|
pulses = int(body["object"]["pulse_count"])
|
2026-05-07 00:13:17 +02:00
|
|
|
|
2026-05-09 15:36:31 +02:00
|
|
|
device_id = get_device_id(db_conn, dev_eui)
|
|
|
|
|
insert_reading(db_conn, device_id, pulses)
|
2026-05-07 00:13:17 +02:00
|
|
|
|
2026-05-09 15:36:31 +02:00
|
|
|
log.info(
|
|
|
|
|
f"[UP] dev_eui={dev_eui} | device_id={device_id} | pulses={pulses}| relevé inséré"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
log.exception(f"Erreur traitement message : {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ── Main ─────────────────────────────────────────────────────────
|
2026-05-07 00:13:17 +02:00
|
|
|
if __name__ == "__main__":
|
2026-05-09 15:36:31 +02:00
|
|
|
db_conn = get_db()
|
|
|
|
|
|
2026-05-07 00:13:17 +02:00
|
|
|
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
|
|
|
|
mqttc.on_connect = on_connect
|
|
|
|
|
mqttc.on_message = on_message
|
2026-05-09 15:36:31 +02:00
|
|
|
mqttc.reconnect_delay_set(min_delay=1, max_delay=30)
|
2026-05-07 00:13:17 +02:00
|
|
|
|
2026-05-09 15:36:31 +02:00
|
|
|
mqttc.connect(MQTT_HOST, MQTT_PORT, 60)
|
|
|
|
|
mqttc.loop_forever()
|