1"""MQTTConnector module for connecting to MQTT topics and caching messages.
3Provides the MQTTConnector class for subscribing to topics, receiving messages,
4and storing the latest payload for each topic.
9from urllib.parse
import urlparse
11from aas_standard_parser.aid_parser
import BasicAuthenticationDetails, IAuthenticationDetails
12from paho.mqtt.client
import Client
14logger = logging.getLogger(__name__)
18 """Connector for managing connections to MQTT topics."""
25 def __init__(self, base_url: str, topics: list[str], auth: IAuthenticationDetails):
26 """Initialize the MQTTConnector with broker host and port."""
36 if isinstance(auth, BasicAuthenticationDetails):
37 self.
client.username_pw_set(auth.user, auth.password)
40 self.
client.tls_set(cert_reqs=ssl.CERT_REQUIRED, ca_certs=
None)
41 self.
client.tls_insecure_set(
True)
52 """Extract host, port, and path from broker_url."""
56 scheme = parsed.scheme
or "mqtt"
59 host = parsed.hostname
62 defaults = {
"mqtt": 1883,
"mqtts": 8883,
"ws": 80,
"wss": 443}
63 port = parsed.port
or defaults.get(scheme, 1883)
66 path = parsed.path
or "/" if "ws" in parsed.scheme
else None
69 use_tls = scheme
in (
"mqtts",
"wss")
71 return host, port, path, use_tls
74 """Determine if plain MQTT or MQTT over WebSocket is needed."""
80 """Connect to the MQTT broker and subscribe to all topics.
82 This method should be called after initializing the MQTTConnector.
85 logger.debug(f
"Connecting to MQTT broker at '{self.base_url}:{self.port}'")
87 except Exception
as e:
88 raise ConnectionError(f
"Error connecting to MQTT broker at '{self.base_url}': {e}")
91 """Handle response from the server.
93 :param client: The client instance for this callback.
94 :param userdata: The private user data as set in Client() or userdata_set().
95 :param flags: Response flags sent by the broker.
96 :param rc: The connection result.
98 logger.info(f
"Connected with result code {rc}")
104 self.
client.subscribe(topic)
105 logger.info(f
"Subscribed to topic: {topic}")
108 """Handle incoming messages from subscribed topics.
110 :param client: The client instance for this callback.
111 :param userdata: The private user data as set in Client() or userdata_set().
112 :param message: The message instance containing topic and payload.
114 topic = message.topic
115 payload = message.payload.decode(
"utf-8")
116 logger.info(f
"Received message '{payload}' on topic '{topic}'")
119 self.
cache[topic] = payload
122 """Start the MQTT client loop in a separate thread for non-blocking operation.
124 :return: True if the loop started successfully, False otherwise.
126 return self.
client.loop_start()
129 """Stop the MQTT client loop and disconnect from the broker."""
134 """Disconnect from the MQTT broker gracefully."""
138 """Clean up resources and disconnect from the MQTT broker.
140 This method should be called when the connector is no longer needed
141 to ensure proper cleanup of resources.
146 self.
client.unsubscribe(topic)
156 except (OSError, ConnectionError, RuntimeError)
as e:
157 logger.error(f
"Error during disposal: {e}")
160 """Context manager entry point.
162 :return: The MQTTConnector instance.
166 def __exit__(self, exc_type, exc_val, exc_tb):
167 """Context manager exit point - ensures proper cleanup.
169 :param exc_type: Exception type if an exception was raised.
170 :param exc_val: Exception value if an exception was raised.
171 :param exc_tb: Exception traceback if an exception was raised.
176 """Add topics to the MQTTConnector."""
180 """Retrieve the cached value for a specific topic.
182 :param topic: The topic to retrieve the cached value for.
183 :return: The cached value if it exists, otherwise None.
191 def publish(self, topic: str, payload: str):
192 """Publish a message to a specific topic.
194 :param topic: The topic to publish the message to.
195 :param payload: The message payload to be published.
Connector for managing connections to MQTT topics.
get_cached_value(self, topic)
Retrieve the cached value for a specific topic.
start_async(self)
Start the MQTT client loop in a separate thread for non-blocking operation.
stop(self)
Stop the MQTT client loop and disconnect from the broker.
_on_message(self, client, userdata, message)
Handle incoming messages from subscribed topics.
dispose(self)
Clean up resources and disconnect from the MQTT broker.
publish(self, str topic, str payload)
Publish a message to a specific topic.
__exit__(self, exc_type, exc_val, exc_tb)
Context manager exit point - ensures proper cleanup.
disconnect(self)
Disconnect from the MQTT broker gracefully.
connect(self)
Connect to the MQTT broker and subscribe to all topics.
__init__(self, str base_url, list[str] topics, IAuthenticationDetails auth)
Initialize the MQTTConnector with broker host and port.
_on_connect(self, client, userdata, flags, rc)
Handle response from the server.
_detect_transport(self)
Determine if plain MQTT or MQTT over WebSocket is needed.
__enter__(self)
Context manager entry point.
_parse_url(self)
Extract host, port, and path from broker_url.
add_topics(self, topics)
Add topics to the MQTTConnector.