Skip to main content

MQTT client implementation for Python - part of Direct Method Library

Project description

direct-method-mqtt-python

Python MQTT client implementation - part of the Direct Method Library.

Installation

Using pip (recommended)

pip install direct-method-mqtt-python

Development Installation

If you encounter permission issues with system Python, use a virtual environment:

# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install the package
pip install direct-method-mqtt-python
# Or for development: pip install -e .

Quick Start

from direct_method_mqtt import DirectMethodMqttClient

# Create client instance
client = DirectMethodMqttClient("localhost", 1883, "test/topic")

# Set up message handler
def on_message(topic, message):
    print(f"Received: {message} on topic: {topic}")

client.on_message_received(on_message)

# Connect and start using the client
try:
    client.connect()
    client.subscribe()
    client.publish("Hello from Python!")
    
    # Keep the application running to receive messages
    # In a real application, you might want to handle this differently
    import time
    time.sleep(5)
    
finally:
    client.disconnect()

Using as Context Manager

from direct_method_mqtt import DirectMethodMqttClient

def handle_message(topic, message):
    print(f"Got message: {message} on {topic}")

# Automatically handles connection and cleanup
with DirectMethodMqttClient("localhost", 1883, "test/topic") as client:
    client.on_message_received(handle_message)
    client.subscribe()
    client.publish("Hello World!")
    
    import time
    time.sleep(2)  # Wait for potential responses

API Reference

Constructor

DirectMethodMqttClient(broker_host, broker_port=1883, topic="", client_id=None)
  • broker_host (str): MQTT broker hostname or IP address
  • broker_port (int, optional): MQTT broker port (default: 1883)
  • topic (str): Topic to subscribe and publish to
  • client_id (str, optional): Unique client identifier (auto-generated if not provided)

Methods

connect(timeout=5.0) -> None

Connect to the MQTT broker.

  • timeout (float): Connection timeout in seconds

disconnect() -> None

Disconnect from the MQTT broker.

publish(message: str) -> None

Publish a message to the configured topic.

subscribe() -> None

Subscribe to the configured topic.

on_message_received(callback: MessageCallback) -> None

Set a callback function to handle received messages.

  • callback: Function that accepts (topic: str, message: str)

Properties

is_connected: bool

Get the current connection status.

topic: str

Get the configured topic.

broker_info: Tuple[str, int]

Get the broker connection details as (host, port).

client_id: str

Get the client ID.

Error Handling

The client includes comprehensive error handling:

from direct_method_mqtt import DirectMethodMqttClient

client = DirectMethodMqttClient("localhost", 1883, "test/topic")

try:
    client.connect(timeout=10.0)
    client.publish("test message")
except ConnectionError as e:
    print(f"Connection failed: {e}")
except RuntimeError as e:
    print(f"MQTT operation failed: {e}")
except ValueError as e:
    print(f"Invalid parameter: {e}")
finally:
    client.disconnect()

Common exceptions:

  • ConnectionError: Connection to broker failed
  • RuntimeError: MQTT operations when not connected, publish/subscribe failures
  • ValueError: Invalid constructor parameters or empty messages

Advanced Usage

Custom Client ID and Logging

import logging
from direct_method_mqtt import DirectMethodMqttClient

# Enable debug logging
logging.basicConfig(level=logging.DEBUG)

client = DirectMethodMqttClient(
    "mqtt.example.com", 
    1883, 
    "sensors/temperature",
    "my-unique-client-id"
)

def temperature_handler(topic, message):
    try:
        temp = float(message)
        print(f"Temperature reading: {temp}°C")
    except ValueError:
        print(f"Invalid temperature data: {message}")

client.on_message_received(temperature_handler)

Robust Connection with Retry Logic

import time
from direct_method_mqtt import DirectMethodMqttClient

def connect_with_retry(client, max_retries=3, retry_delay=5.0):
    """Connect to MQTT broker with retry logic."""
    for attempt in range(max_retries):
        try:
            client.connect(timeout=10.0)
            print("Connected successfully!")
            return True
        except ConnectionError as e:
            print(f"Connection attempt {attempt + 1} failed: {e}")
            if attempt < max_retries - 1:
                print(f"Retrying in {retry_delay} seconds...")
                time.sleep(retry_delay)
    
    print("Failed to connect after all retries")
    return False

client = DirectMethodMqttClient("localhost", 1883, "app/messages")

if connect_with_retry(client):
    try:
        client.subscribe()
        client.publish("Connection established")
        
        # Your application logic here
        time.sleep(10)
        
    finally:
        client.disconnect()

Message Processing with JSON

import json
from direct_method_mqtt import DirectMethodMqttClient

def process_json_message(topic, message):
    """Process JSON messages safely."""
    try:
        data = json.loads(message)
        print(f"Received data: {data}")
        
        # Process specific message types
        if data.get("type") == "sensor_reading":
            print(f"Sensor {data['sensor_id']}: {data['value']} {data['unit']}")
        elif data.get("type") == "alert":
            print(f"ALERT: {data['message']}")
        else:
            print(f"Unknown message type: {data.get('type')}")
            
    except json.JSONDecodeError:
        print(f"Received non-JSON message: {message}")
    except KeyError as e:
        print(f"Missing required field in message: {e}")

client = DirectMethodMqttClient("localhost", 1883, "data/json")
client.on_message_received(process_json_message)

with client:
    client.subscribe()
    
    # Send some test messages
    test_messages = [
        '{"type": "sensor_reading", "sensor_id": "temp01", "value": 23.5, "unit": "°C"}',
        '{"type": "alert", "message": "Temperature too high!"}',
        '{"type": "unknown", "data": "some data"}',
        'not a json message'
    ]
    
    for msg in test_messages:
        client.publish(msg)
        time.sleep(1)
    
    time.sleep(5)  # Wait for message processing

Threading Considerations

The client is thread-safe for most operations, but be aware that:

  • Message callbacks are executed in the MQTT client's background thread
  • Connection state changes are protected by internal locking
  • If you need to publish from within a message callback, it's safe to do so
from direct_method_mqtt import DirectMethodMqttClient
import threading

class MqttHandler:
    def __init__(self, client):
        self.client = client
        self.message_count = 0
        self.lock = threading.Lock()
    
    def handle_message(self, topic, message):
        with self.lock:
            self.message_count += 1
            print(f"Message #{self.message_count}: {message}")
            
            # Safe to publish from callback
            if message.lower() == "ping":
                self.client.publish("pong")

client = DirectMethodMqttClient("localhost", 1883, "test/echo")
handler = MqttHandler(client)

with client:
    client.on_message_received(handler.handle_message)
    client.subscribe()
    client.publish("ping")
    
    time.sleep(2)

Requirements

  • Python 3.9 or higher
  • paho-mqtt 1.6.0 or higher

Type Hints

This package includes full type hints for better IDE support and type checking:

from typing import Optional
from direct_method_mqtt import DirectMethodMqttClient, MessageCallback

def create_client(host: str, port: int = 1883) -> DirectMethodMqttClient:
    return DirectMethodMqttClient(host, port, "my/topic")

def my_callback(topic: str, message: str) -> None:
    print(f"{topic}: {message}")

client = create_client("localhost")
client.on_message_received(my_callback)

License

MIT License - see the LICENSE file for details.

Contributing

This is part of the Direct Method Library demo project. See the main repository for contribution guidelines.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

direct_method_mqtt_python-1.0.0.tar.gz (10.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

direct_method_mqtt_python-1.0.0-py3-none-any.whl (7.9 kB view details)

Uploaded Python 3

File details

Details for the file direct_method_mqtt_python-1.0.0.tar.gz.

File metadata

File hashes

Hashes for direct_method_mqtt_python-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f0696eaa97a7070b6a3d2a4d95bf1688804d11264d2e2702ae79ed8836fade6b
MD5 832ea8ff8b6897dc1e41653afe269a27
BLAKE2b-256 fc825611dfa62bf42e5cf58c98c506aaf0cd3ef7e0caeac55b7ed731a1de66f1

See more details on using hashes here.

File details

Details for the file direct_method_mqtt_python-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for direct_method_mqtt_python-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b43b0291288f60542847d9819d0b52b4fb1aca2c6b36c1c1ed7d012ab6864234
MD5 90f000fd9d9a5e0c9f2b1674fc7feb93
BLAKE2b-256 0424935a26823ded1cc4bae305841750bcfc3400c59f55a2ef7ab24ceeb45464

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page