gmqtt

repository·master·Indexed 19 days ago

https://github.com/wialon/gmqtt

A Python asynchronous MQTT client implementation that supports the MQTT 5.0 protocol and is compatible with uvloop. It provides a Client class for managing connections, subscriptions, and event handling, with support for MQTT 5.0 connection and publish properties, asynchronous on_message callbacks, and configurable reconnection behavior.

Tokens
3.4K
Snippets
15
Records
17
Agent score
66%

What's inside gmqtt

  1. Run the test suite

    master

    To run the unit tests for gmqtt, you must first install the package with the [test] extra dependencies.

    Note: The tests require a flespi.io account. You must provide your flespi.io token via the USERNAME environment variable.

    # Install test dependencies
    pip3 install .[test]
    
    # Set your flespi.io token
    export USERNAME=YOUR_FLESPI_IO_TOKEN
    
    # Run tests
    pytest-3 tests
  2. Get started with gmqtt

    master

    This example demonstrates a basic asynchronous MQTT client that connects to a broker, subscribes to a topic, and prints received messages. It also shows how to integrate uvloop for improved event loop performance.

    import asyncio
    import os
    import signal
    import time
    
    from gmqtt import Client as MQTTClient
    
    # gmqtt also compatibility with uvloop  
    import uvloop
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    
    STOP = asyncio.Event()
    
    def on_connect(client, flags, rc, properties):
        print('Connected')
        client.subscribe('TEST/#', qos=0)
    
    def on_message(client, topic, payload, qos, properties):
        print('RECV MSG:', payload)
    
    def on_disconnect(client, packet, exc=None):
        print('Disconnected')
    
    def on_subscribe(client, mid, qos, properties):
        print('SUBSCRIBED')
    
    def ask_exit(*args):
        STOP.set()
    
    async def main(broker_host, token):
        client = MQTTClient("client-id")
    
        client.on_connect = on_connect
        client.on_message = on_message
        client.on_disconnect = on_disconnect
        client.on_subscribe = on_subscribe
    
        client.set_auth_credentials(token, None)
        await client.connect(broker_host)
    
        client.publish('TEST/TIME', str(time.time()), qos=1)
    
        await STOP.wait()
        await client.disconnect()
    
    
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
    
        host = 'mqtt.flespi.io'
        token = os.environ.get('FLESPI_TOKEN')
    
        loop.add_signal_handler(signal.SIGINT, ask_exit)
        loop.add_signal_handler(signal.SIGTERM, ask_exit)
    
        loop.run_until_complete(main(host, token))
  3. Set up a local development environment

    master

    To contribute to gmqtt, it is recommended to use a Python virtual environment. Follow these steps to clone your fork, set up the environment, and install the package in development mode:

    1. Clone your fork of the repository.
    2. Create and activate a Python virtual environment.
    3. Run setup.py develop to install the package for development.

    To stay up-to-date with the main project, add the upstream repository as a remote and rebase your local branch periodically.

    git clone git@github.com:[YOUR_GITHUB_USERNAME]/gmqtt.git
    cd gmqtt
    python3 -m venv .
    source bin/activate
    python3 setup.py develop
    
    # To sync with upstream
    git remote add upstream git@github.com:wialon/gmqtt.git
    git pull --rebase upstream master
  4. Configure Client connection properties

    master

    When initializing the MQTTClient, you can pass MQTT 5.0 connection properties as keyword arguments. These are stored in client.properties after connection.

    • session_expiry_interval (int): Session expiry in seconds. 0 or absent means the session ends when the network connection closes. 0xFFFFFFFF means the session never expires.
    • receive_maximum (int): Limits the number of QoS 1 and QoS 2 publications processed concurrently.
    • user_property (tuple(str, str)): Key-value pairs for diagnostic information.
    • maximum_packet_size (int): Informs the server of the maximum packet size (in bytes) the client will process.
    client = gmqtt.Client("lenkaklient", receive_maximum=24000, session_expiry_interval=60, user_property=('myid', '12345'))
  5. Configure MQTT 5.0 Session Expiry Interval

    master

    In MQTT 5.0, the session_expiry_interval determines how long the broker maintains the session after the client disconnects.

    • Value 0 (or absent): The session ends when the network connection is closed.
    • Value 0xFFFFFFFF: The session never expires.
    • Server Override: The broker may override your requested value in the CONNACK packet. You can check the effective interval using the client.session_expiry_interval property after connecting.
  6. Configure reconnection behavior

    master

    By default, the client attempts to reconnect indefinitely. You can customize the number of retries and the delay between attempts using set_config.

    • reconnect_retries (int): Number of attempts. Default is -1 (infinity).
    • reconnect_delay (int): Delay in seconds. Default is 6.
    client = MQTTClient("client-id")
    client.set_config({'reconnect_retries': 10, 'reconnect_delay': 60})
  7. Configure Subscribe properties

    master
    When subscribing, you can use the subscription_identifier (int). If specified, the server must send these identifiers in the resulting published messages for overlapping subscriptions.
  8. Use asynchronous on_message callbacks

    master

    You can define on_message as an async function. To signal successful processing, the callback must return a valid PUBACK code (e.g., 0 for success).

    async def on_message(client, topic, payload, qos, properties):
        # Process message
        pass
        return 0
  9. Configure MQTT protocol version

    master

    gmqtt uses MQTT version 5.0 by default. If the broker does not support 5.0, the client attempts to downgrade to 3.1.1 and reconnect automatically. You can explicitly force a specific version in the connect method using constants from gmqtt.mqtt.constants.

    from gmqtt.mqtt.constants import MQTTv311
    client = MQTTClient('clientid')
    client.set_auth_credentials(token, None)
    await client.connect(broker_host, 1883, keepalive=60, version=MQTTv311)
  10. Configure Publish properties

    master

    When publishing messages, you can include MQTT 5.0 properties. These properties are sent in the publish packet and will be passed to the on_message callback on the receiving end.

    • message_expiry_interval (int): Lifetime of the application message in seconds.
    • content_type (unicode): UTF-8 string describing the content of the message.
    • user_property (tuple(str, str)): Key-value pairs.
    • subscription_identifier (int): Sent by the broker.
    • topic_alias (int): Allows publishing with an empty string topic after an initial message with a full topic string and a topic_alias.
    # Example publishing with properties
    client.publish('TEST/TIME', str(time.time()), qos=1, retain=True, message_expiry_interval=60, content_type='json')
  11. Handle MQTT events with callbacks

    master

    The Client exposes several properties that allow you to assign callback functions for MQTT events. These callbacks are triggered by the internal MqttPackageHandler.

    EventCallback Signature
    on_connecton_connect(client, flags, rc, properties)
    on_messageon_message(client, topic, payload, qos, properties)
    on_disconnecton_disconnect(client, packet, exc)
    on_subscribeon_subscribe(client, mid, qos, properties)
    on_unsubscribeon_unsubscribe(client, mid, qos)

    Note: The on_message callback receives the payload as bytes.

    async def on_message(client, topic, payload, qos, properties):
        print(f"Received {payload} on {topic}")
    
    client.on_message = on_message