From dfe4adad1cb56346d0f842a04ef6b18c0c70e414 Mon Sep 17 00:00:00 2001 From: Lloyd Date: Mon, 5 Jan 2026 10:47:14 +0000 Subject: [PATCH] feat: Enhance MQTT configuration with TLS/SSL support and update logging --- config.yaml.example | 58 +++++++++++++++-------- repeater/data_acquisition/mqtt_handler.py | 36 +++++++++++++- 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/config.yaml.example b/config.yaml.example index 2d4e2c8..82d1cd0 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -164,28 +164,49 @@ duty_cycle: max_airtime_per_minute: 3600 +# MQTT Publishing Configuration (Optional) +mqtt: + # Enable/disable MQTT publishing + enabled: false + + # MQTT broker settings + broker: "localhost" + port: 1883 # Use 8883 for TLS/SSL + + # Authentication (optional) + username: null + password: null + + # TLS/SSL configuration (optional) + # For public brokers with trusted certificates, just enable TLS: + # tls: + # enabled: true + tls: + enabled: false + + # Advanced TLS options (usually not needed for public brokers): + + # Custom CA certificate for server verification + # Leave null to use system default CA certificates (recommended) + ca_cert: null # e.g., "/etc/ssl/certs/ca-certificates.crt" + + # Client certificate and key for mutual TLS (rarely needed) + client_cert: null # e.g., "/etc/pymc/client.crt" + client_key: null # e.g., "/etc/pymc/client.key" + + # Skip certificate verification (insecure, not recommended) + insecure: false + + # Base topic for publishing + # Messages will be published to: {base_topic}/{node_name}/{packet|advert} + base_topic: "meshcore/repeater" + + # Storage Configuration storage: # Directory for persistent storage files (SQLite, RRD) storage_dir: "/var/lib/pymc_repeater" - # MQTT publishing configuration (optional) - mqtt: - # Enable/disable MQTT publishing - enabled: false - - # MQTT broker settings - broker: "localhost" - port: 1883 - - # Authentication (optional) - username: null - password: null - - # Base topic for publishing - # Messages will be published to: {base_topic}/{node_name}/{packet|advert} - base_topic: "meshcore/repeater" - # Data retention settings retention: # Clean up SQLite records older than this many days @@ -197,9 +218,6 @@ storage: # - 1 hour resolution for 1 year - - - letsmesh: enabled: false iata_code: "Test" # e.g., "SFO", "LHR", "Test" diff --git a/repeater/data_acquisition/mqtt_handler.py b/repeater/data_acquisition/mqtt_handler.py index 27fc5f3..fe88e1d 100644 --- a/repeater/data_acquisition/mqtt_handler.py +++ b/repeater/data_acquisition/mqtt_handler.py @@ -1,5 +1,6 @@ import json import logging +import ssl from typing import Dict, Any, Optional try: @@ -30,6 +31,38 @@ class MQTTHandler: try: self.client = mqtt.Client() + # Configure TLS/SSL if enabled + tls_config = self.mqtt_config.get("tls", {}) + if tls_config.get("enabled", False): + tls_params = { + "cert_reqs": ssl.CERT_REQUIRED, + "tls_version": ssl.PROTOCOL_TLS, + } + + # CA certificate for server verification (optional - uses system certs if not specified) + ca_cert = tls_config.get("ca_cert") + if ca_cert: + tls_params["ca_certs"] = ca_cert + logger.info("Using custom CA certificate for MQTT TLS") + else: + logger.info("Using system default CA certificates for MQTT TLS") + + # Client certificate and key (for mutual TLS) + client_cert = tls_config.get("client_cert") + client_key = tls_config.get("client_key") + if client_cert: + tls_params["certfile"] = client_cert + if client_key: + tls_params["keyfile"] = client_key + + # Allow insecure connections (skip cert verification) + if tls_config.get("insecure", False): + tls_params["cert_reqs"] = ssl.CERT_NONE + logger.warning("MQTT TLS certificate verification disabled (insecure mode)") + + self.client.tls_set(**tls_params) + logger.info("MQTT TLS/SSL configured") + username = self.mqtt_config.get("username") password = self.mqtt_config.get("password") if username: @@ -41,7 +74,8 @@ class MQTTHandler: self.client.connect(broker, port, 60) self.client.loop_start() - logger.info(f"MQTT client connected to {broker}:{port}") + secure = "(TLS)" if tls_config.get("enabled", False) else "" + logger.info(f"MQTT client connected to {broker}:{port} {secure}") except Exception as e: logger.error(f"Failed to initialize MQTT: {e}")