Files
full-stack-fastapi/backend/app/mqtt/ingestor.py

79 lines
2.0 KiB
Python

from __future__ import annotations
import logging
import paho.mqtt.client as mqtt # type: ignore[import-not-found,import-untyped]
from sqlmodel import Session
from app.core.config import settings
from app.core.db import engine
from app.mqtt.repository import insert_raw_message
from app.mqtt.topic import extract_device_id
logger = logging.getLogger(__name__)
def _on_connect(
client: mqtt.Client,
_userdata: object,
_flags: dict[str, int],
reason_code: int,
_properties: mqtt.Properties | None = None,
) -> None:
if reason_code != 0:
logger.error("MQTT connect failed: rc=%s", reason_code)
return
logger.info(
"Connected to MQTT broker %s:%s", settings.MQTT_HOST, settings.MQTT_PORT
)
client.subscribe(settings.MQTT_TOPIC_PATTERN, qos=1)
def _on_message(
_client: mqtt.Client,
_userdata: object,
message: mqtt.MQTTMessage,
) -> None:
try:
device_id = extract_device_id(message.topic)
except ValueError:
logger.warning("Skipping unexpected topic: %s", message.topic)
return
with Session(engine) as session:
insert_raw_message(
session=session,
device_id=device_id,
topic=message.topic,
payload=bytes(message.payload),
qos=message.qos,
retain=message.retain,
)
def create_client() -> mqtt.Client:
client = mqtt.Client(
callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
client_id=settings.MQTT_CLIENT_ID,
clean_session=False,
)
if settings.MQTT_USERNAME:
client.username_pw_set(settings.MQTT_USERNAME, settings.MQTT_PASSWORD)
client.on_connect = _on_connect
client.on_message = _on_message
client.reconnect_delay_set(min_delay=1, max_delay=30)
return client
def run() -> None:
logging.basicConfig(level=logging.INFO)
client = create_client()
client.connect(settings.MQTT_HOST, settings.MQTT_PORT, keepalive=60)
client.loop_forever()
if __name__ == "__main__":
run()