M6-T06: extend MqttManager with subscribe + DSMR ingest

- mqtt.py: subscription registry, on_message dispatch (swallows handler
  errors), re-subscribe on (re)connect; publish/connect/disconnect/reconnect
  unchanged.
- app/services/dsmr_ingest.py: handle_message stores the full telegram frame
  (no allowlist; gas/phases/null preserved), 10s downsample by timestamp.second,
  source_id idempotency (select + IntegrityError rollback). Net-thread safe.
- main.py registers the DSMR subscription only when dsmr_ingest_enabled.
This commit is contained in:
2026-06-23 21:52:57 +02:00
parent 7e266a21eb
commit ef48032adb
6 changed files with 920 additions and 1 deletions
+17
View File
@@ -28,6 +28,7 @@ from app.config import get_settings
from app.integrations.mqtt import mqtt_manager
from app.services.auth import AuthBootstrapError, initialize_auth_schema
from app.services.config_page import build_runtime_settings, seed_missing_config_from_bootstrap, sync_app_hostname_from_bootstrap
from app.services.dsmr_ingest import handle_message as dsmr_handle_message
from app.services.public_ip import check_public_ipv4_and_notify
from app.services.modbus_poll import poll_all_enabled_devices, BASE_POLL_TICK_SECONDS
from app.services.ha_discovery import publish_discovery, publish_states
@@ -201,6 +202,22 @@ async def lifespan(_: FastAPI):
_startup_session.close()
mqtt_manager.connect(_startup_runtime_settings)
# DSMR ingest: subscribe to the configured MQTT topic when enabled.
# The handler captures a snapshot of the current runtime settings (for the
# dsmr_sample_interval_s value). Runtime setting changes take effect after
# a server restart or an explicit reconnect — consistent with other MQTT
# configuration in this project.
if _startup_runtime_settings.dsmr_ingest_enabled:
_dsmr_topic = _startup_runtime_settings.dsmr_mqtt_topic
_dsmr_settings_snapshot = _startup_runtime_settings
mqtt_manager.subscribe(
_dsmr_topic,
lambda payload: dsmr_handle_message(payload, _dsmr_settings_snapshot),
)
logger.info("DSMR ingest enabled — subscribed to topic=%s.", _dsmr_topic)
else:
logger.debug("DSMR ingest disabled — not subscribing to DSMR topic.")
yield
# MQTT: clean shutdown before the process exits.