Giter Club home page Giter Club logo

paho.mqtt.python's Introduction

Eclipse Paho™ MQTT Python Client

The full documentation is available here.

Warning breaking change - Release 2.0 contains a breaking change; see the release notes and migration details.

This document describes the source code for the Eclipse Paho MQTT Python client library, which implements versions 5.0, 3.1.1, and 3.1 of the MQTT protocol.

This code provides a client class which enables applications to connect to an MQTT broker to publish messages, and to subscribe to topics and receive published messages. It also provides some helper functions to make publishing one off messages to an MQTT server very straightforward.

It supports Python 3.7+.

The MQTT protocol is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. Designed as an extremely lightweight publish/subscribe messaging transport, it is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium.

Paho is an Eclipse Foundation project.

Contents

Installation

The latest stable version is available in the Python Package Index (PyPi) and can be installed using

pip install paho-mqtt

Or with virtualenv:

virtualenv paho-mqtt
source paho-mqtt/bin/activate
pip install paho-mqtt

To obtain the full code, including examples and tests, you can clone the git repository:

git clone https://github.com/eclipse/paho.mqtt.python

Once you have the code, it can be installed from your repository as well:

cd paho.mqtt.python
pip install -e .

To perform all tests (including MQTT v5 tests), you also need to clone paho.mqtt.testing in paho.mqtt.python folder:

git clone https://github.com/eclipse/paho.mqtt.testing.git
cd paho.mqtt.testing
git checkout a4dc694010217b291ee78ee13a6d1db812f9babd

Known limitations

The following are the known unimplemented MQTT features.

When clean_session is False, the session is only stored in memory and not persisted. This means that when the client is restarted (not just reconnected, the object is recreated usually because the program was restarted) the session is lost. This results in a possible message loss.

The following part of the client session is lost:

  • QoS 2 messages which have been received from the server, but have not been completely acknowledged.

    Since the client will blindly acknowledge any PUBCOMP (last message of a QoS 2 transaction), it won't hang but will lose this QoS 2 message.

  • QoS 1 and QoS 2 messages which have been sent to the server, but have not been completely acknowledged.

    This means that messages passed to publish() may be lost. This could be mitigated by taking care that all messages passed to publish() have a corresponding on_publish() call or use wait_for_publish.

    It also means that the broker may have the QoS2 message in the session. Since the client starts with an empty session it don't know it and will reuse the mid. This is not yet fixed.

Also, when clean_session is True, this library will republish QoS > 0 message across network reconnection. This means that QoS > 0 message won't be lost. But the standard says that we should discard any message for which the publish packet was sent. Our choice means that we are not compliant with the standard and it's possible for QoS 2 to be received twice.

You should set clean_session = False if you need the QoS 2 guarantee of only one delivery.

Usage and API

Detailed API documentation is available online or could be built from docs/ and samples are available in the examples directory.

The package provides two modules, a full Client and few helpers for simple publishing or subscribing.

Getting Started

Here is a very simple example that subscribes to the broker $SYS topic tree and prints out the resulting messages:

import paho.mqtt.client as mqtt

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, reason_code, properties):
    print(f"Connected with result code {reason_code}")
    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe("$SYS/#")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_connect = on_connect
mqttc.on_message = on_message

mqttc.connect("mqtt.eclipseprojects.io", 1883, 60)

# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
mqttc.loop_forever()

Client

You can use the client class as an instance, within a class or by subclassing. The general usage flow is as follows:

  • Create a client instance
  • Connect to a broker using one of the connect*() functions
  • Call one of the loop*() functions to maintain network traffic flow with the broker
  • Use subscribe() to subscribe to a topic and receive messages
  • Use publish() to publish messages to the broker
  • Use disconnect() to disconnect from the broker

Callbacks will be called to allow the application to process events as necessary. These callbacks are described below.

Network loop

These functions are the driving force behind the client. If they are not called, incoming network data will not be processed and outgoing network data will not be sent. There are four options for managing the network loop. Three are described here, the fourth in "External event loop support" below. Do not mix the different loop functions.

loop_start() / loop_stop()
mqttc.loop_start()

while True:
    temperature = sensor.blocking_read()
    mqttc.publish("paho/temperature", temperature)

mqttc.loop_stop()

These functions implement a threaded interface to the network loop. Calling loop_start() once, before or after connect*(), runs a thread in the background to call loop() automatically. This frees up the main thread for other work that may be blocking. This call also handles reconnecting to the broker. Call loop_stop() to stop the background thread. The loop is also stopped if you call disconnect().

loop_forever()
mqttc.loop_forever(retry_first_connection=False)

This is a blocking form of the network loop and will not return until the client calls disconnect(). It automatically handles reconnecting.

Except for the first connection attempt when using connect_async, use retry_first_connection=True to make it retry the first connection.

Warning: This might lead to situations where the client keeps connecting to an non existing host without failing.

loop()
run = True
while run:
    rc = mqttc.loop(timeout=1.0)
    if rc != 0:
        # need to handle error, possible reconnecting or stopping the application

Call regularly to process network events. This call waits in select() until the network socket is available for reading or writing, if appropriate, then handles the incoming/outgoing data. This function blocks for up to timeout seconds. timeout must not exceed the keepalive value for the client or your client will be regularly disconnected by the broker.

Using this kind of loop, require you to handle reconnection strategie.

Callbacks

The interface to interact with paho-mqtt include various callback that are called by the library when some events occur.

The callbacks are functions defined in your code, to implement the require action on those events. This could be simply printing received message or much more complex behaviour.

Callbacks API is versioned, and the selected version is the CallbackAPIVersion you provided to Client constructor. Currently two version are supported:

  • CallbackAPIVersion.VERSION1: it's the historical version used in paho-mqtt before version 2.0. It's the API used before the introduction of CallbackAPIVersion. This version is deprecated and will be removed in paho-mqtt version 3.0.
  • CallbackAPIVersion.VERSION2: This version is more consistent between protocol MQTT 3.x and MQTT 5.x. It's also much more usable with MQTT 5.x since reason code and properties are always provided when available. It's recommended for all user to upgrade to this version. It's highly recommended for MQTT 5.x user.

The following callbacks exists:

  • `on_connect()`: called when the CONNACK from the broker is received. The call could be for a refused connection, check the reason_code to see if the connection is successful or rejected.
  • `on_connect_fail(): called by `loop_forever() and loop_start() when the TCP connection failed to establish. This callback is not called when using connect() or reconnect() directly. It's only called following an automatic (re)connection made by loop_start() and loop_forever()
  • `on_disconnect()`: called when the connection is closed.
  • `on_message()`: called when a MQTT message is received from the broker.
  • `on_publish()`: called when an MQTT message was sent to the broker. Depending on QoS level the callback is called at different moment:
    • For QoS == 0, it's called as soon as the message is sent over the network. This could be before the corresponding publish() return.
    • For QoS == 1, it's called when the corresponding PUBACK is received from the broker
    • For QoS == 2, it's called when the corresponding PUBCOMP is received from the broker
  • `on_subscribe()`: called when the SUBACK is received from the broker
  • `on_unsubscribe()`: called when the UNSUBACK is received from the broker
  • `on_log()`: called when the library log a message
  • on_socket_open, on_socket_close, on_socket_register_write, `on_socket_unregister_write`: callbacks used for external loop support. See below for details.

For the signature of each callback, see the online documentation.

Subscriber example
import paho.mqtt.client as mqtt

def on_subscribe(client, userdata, mid, reason_code_list, properties):
    # Since we subscribed only for a single channel, reason_code_list contains
    # a single entry
    if reason_code_list[0].is_failure:
        print(f"Broker rejected you subscription: {reason_code_list[0]}")
    else:
        print(f"Broker granted the following QoS: {reason_code_list[0].value}")

def on_unsubscribe(client, userdata, mid, reason_code_list, properties):
    # Be careful, the reason_code_list is only present in MQTTv5.
    # In MQTTv3 it will always be empty
    if len(reason_code_list) == 0 or not reason_code_list[0].is_failure:
        print("unsubscribe succeeded (if SUBACK is received in MQTTv3 it success)")
    else:
        print(f"Broker replied with failure: {reason_code_list[0]}")
    client.disconnect()

def on_message(client, userdata, message):
    # userdata is the structure we choose to provide, here it's a list()
    userdata.append(message.payload)
    # We only want to process 10 messages
    if len(userdata) >= 10:
        client.unsubscribe("$SYS/#")

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Failed to connect: {reason_code}. loop_forever() will retry connection")
    else:
        # we should always subscribe from on_connect callback to be sure
        # our subscribed is persisted across reconnections.
        client.subscribe("$SYS/#")

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.on_subscribe = on_subscribe
mqttc.on_unsubscribe = on_unsubscribe

mqttc.user_data_set([])
mqttc.connect("mqtt.eclipseprojects.io")
mqttc.loop_forever()
print(f"Received the following message: {mqttc.user_data_get()}")
publisher example
import time
import paho.mqtt.client as mqtt

def on_publish(client, userdata, mid, reason_code, properties):
    # reason_code and properties will only be present in MQTTv5. It's always unset in MQTTv3
    try:
        userdata.remove(mid)
    except KeyError:
        print("on_publish() is called with a mid not present in unacked_publish")
        print("This is due to an unavoidable race-condition:")
        print("* publish() return the mid of the message sent.")
        print("* mid from publish() is added to unacked_publish by the main thread")
        print("* on_publish() is called by the loop_start thread")
        print("While unlikely (because on_publish() will be called after a network round-trip),")
        print(" this is a race-condition that COULD happen")
        print("")
        print("The best solution to avoid race-condition is using the msg_info from publish()")
        print("We could also try using a list of acknowledged mid rather than removing from pending list,")
        print("but remember that mid could be re-used !")

unacked_publish = set()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_publish = on_publish

mqttc.user_data_set(unacked_publish)
mqttc.connect("mqtt.eclipseprojects.io")
mqttc.loop_start()

# Our application produce some messages
msg_info = mqttc.publish("paho/test/topic", "my message", qos=1)
unacked_publish.add(msg_info.mid)

msg_info2 = mqttc.publish("paho/test/topic", "my message2", qos=1)
unacked_publish.add(msg_info2.mid)

# Wait for all message to be published
while len(unacked_publish):
    time.sleep(0.1)

# Due to race-condition described above, the following way to wait for all publish is safer
msg_info.wait_for_publish()
msg_info2.wait_for_publish()

mqttc.disconnect()
mqttc.loop_stop()

Logger

The Client emit some log message that could be useful during troubleshooting. The easiest way to enable logs is the call enable_logger(). It's possible to provide a custom logger or let the default logger being used.

Example:

import logging
import paho.mqtt.client as mqtt

logging.basicConfig(level=logging.DEBUG)

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.enable_logger()

mqttc.connect("mqtt.eclipseprojects.io", 1883, 60)
mqttc.loop_start()

# Do additional action needed, publish, subscribe, ...
[...]

It's also possible to define a on_log callback that will receive a copy of all log messages. Example:

import paho.mqtt.client as mqtt

def on_log(client, userdata, paho_log_level, messages):
    if paho_log_level == mqtt.LogLevel.MQTT_LOG_ERR:
        print(message)

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_log = on_log

mqttc.connect("mqtt.eclipseprojects.io", 1883, 60)
mqttc.loop_start()

# Do additional action needed, publish, subscribe, ...
[...]

The correspondence with Paho logging levels and standard ones is the following:

Paho logging
MQTT_LOG_ERR logging.ERROR
MQTT_LOG_WARNING logging.WARNING
MQTT_LOG_NOTICE logging.INFO (no direct equivalent)
MQTT_LOG_INFO logging.INFO
MQTT_LOG_DEBUG logging.DEBUG

External event loop support

To support other network loop like asyncio (see examples), the library expose some method and callback to support those use-case.

The following loop method exists:

  • `loop_read`: should be called when the socket is ready for reading.
  • `loop_write`: should be called when the socket is ready for writing AND the library want to write data.
  • `loop_misc`: should be called every few seconds to handle message retrying and pings.

In pseudo code, it give the following:

while run:
    if need_read:
        mqttc.loop_read()
    if need_write:
        mqttc.loop_write()
    mqttc.loop_misc()

    if not need_read and not need_write:
        # But don't wait more than few seconds, loop_misc() need to be called regularly
        wait_for_change_in_need_read_or_write()
    updated_need_read_and_write()

The tricky part is implementing the update of need_read / need_write and wait for condition change. To support this, the following method exists:

  • `socket(): which return the socket object when the TCP connection is open. This call is particularly useful for select_ based loops. See examples/loop_select.py`.
  • `want_write(): return true if there is data waiting to be written. This is close to the need_writew` of above pseudo-code, but you should also check whether the socket is ready for writing.
  • callbacks on_socket_*:

    • `on_socket_open`: called when the socket is opened.
    • `on_socket_close`: called when the socket is about to be closed.
    • `on_socket_register_write`: called when there is data the client want to write on the socket
    • `on_socket_unregister_write`: called when there is no more data to write on the socket.

    Callbacks are particularly useful for event loops where you register or unregister a socket for reading+writing. See examples/loop_asyncio.py for an example.

The callbacks are always called in this order:

  • on_socket_open
  • Zero or more times:
    • on_socket_register_write
    • on_socket_unregister_write
  • on_socket_close

Global helper functions

The client module also offers some global helper functions.

topic_matches_sub(sub, topic) can be used to check whether a topic matches a subscription.

For example:

the topic foo/bar would match the subscription foo/# or +/bar

the topic non/matching would not match the subscription non/+/+

Publish

This module provides some helper functions to allow straightforward publishing of messages in a one-shot manner. In other words, they are useful for the situation where you have a single/multiple messages you want to publish to a broker, then disconnect with nothing else required.

The two functions provided are single() and multiple().

Both functions include support for MQTT v5.0, but do not currently let you set any properties on connection or when sending messages.

Single

Publish a single message to a broker, then disconnect cleanly.

Example:

import paho.mqtt.publish as publish

publish.single("paho/test/topic", "payload", hostname="mqtt.eclipseprojects.io")

Multiple

Publish multiple messages to a broker, then disconnect cleanly.

Example:

from paho.mqtt.enums import MQTTProtocolVersion
import paho.mqtt.publish as publish

msgs = [{'topic':"paho/test/topic", 'payload':"multiple 1"},
    ("paho/test/topic", "multiple 2", 0, False)]
publish.multiple(msgs, hostname="mqtt.eclipseprojects.io", protocol=MQTTProtocolVersion.MQTTv5)

Subscribe

This module provides some helper functions to allow straightforward subscribing and processing of messages.

The two functions provided are simple() and callback().

Both functions include support for MQTT v5.0, but do not currently let you set any properties on connection or when subscribing.

Simple

Subscribe to a set of topics and return the messages received. This is a blocking function.

Example:

import paho.mqtt.subscribe as subscribe

msg = subscribe.simple("paho/test/topic", hostname="mqtt.eclipseprojects.io")
print("%s %s" % (msg.topic, msg.payload))

Using Callback

Subscribe to a set of topics and process the messages received using a user provided callback.

Example:

import paho.mqtt.subscribe as subscribe

def on_message_print(client, userdata, message):
    print("%s %s" % (message.topic, message.payload))
    userdata["message_count"] += 1
    if userdata["message_count"] >= 5:
        # it's possible to stop the program by disconnecting
        client.disconnect()

subscribe.callback(on_message_print, "paho/test/topic", hostname="mqtt.eclipseprojects.io", userdata={"message_count": 0})

Reporting bugs

Please report bugs in the issues tracker at https://github.com/eclipse/paho.mqtt.python/issues.

More information

Discussion of the Paho clients takes place on the Eclipse paho-dev mailing list.

General questions about the MQTT protocol itself (not this library) are discussed in the MQTT Google Group.

There is much more information available via the MQTT community site.

paho.mqtt.python's People

Contributors

akx avatar alexisbrenon avatar antechrestos avatar bertkleewein avatar cclauss avatar gr3at avatar gtmtg avatar hildogjr avatar jamesmyatt avatar jiachin1995 avatar jjasper avatar josiahwitheford avatar jsbergbau avatar lylescott avatar matesh avatar mattbrittan avatar mhhhxx avatar milgra avatar mosauter avatar mrjohannchang avatar mtreinish avatar naveenrobo avatar nickma82 avatar petersilva avatar philipbl avatar pierref avatar ralight avatar swails avatar yawor avatar yoch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

paho.mqtt.python's Issues

Example mqtt applications is not working

migrated from Bugzilla #431698
status RESOLVED severity normal in component MQTT-Python for ---
Reported in version unspecified on platform PC
Assigned to: Roger Light

On 2014-04-01 07:32:09 -0400, Niclas Karlsson wrote:

Hi,

I tried to run the sub.py and pub.py example applications but got the following error:
Traceback (most recent call last):
File "C:\GIT\mqtttools\org.eclipse.paho.mqtt.python\examples\sub.py", line 54, in
mqttc = mqtt.Client()
File "C:\GIT\mqtttools\org.eclipse.paho.mqtt.python\src\paho\mqtt\client.py", line 404, in init
self._sockpairR, self._sockpairW = _socketpair_compat()
File "C:\GIT\mqtttools\org.eclipse.paho.mqtt.python\src\paho\mqtt\client.py", line 262, in _socketpair_compat
sock1.connect(("localhost", port))
File "C:\Python27\lib\socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
error: [Errno 10035] A non-blocking socket operation could not be completed immediately

I ran the latest code, SHA: 48b19a2

On 2014-04-16 16:02:18 -0400, Roger Light wrote:

*** Bug 432949 has been marked as a duplicate of this bug. ***

On 2014-04-16 16:12:36 -0400, Roger Light wrote:

Thanks for the report, I believe this is now fixed in the latest version of the code which you can get from the repository. I would be grateful if you could verify that it works for you as well.

On 2014-04-17 07:35:33 -0400, David Parker wrote:

FWIW, I haven't tried the pub/sub samples, but the latest version of client.py from the repository does fix the same problem I was having on Windows 7 (duplicate bug 432949).

client.connect() just calls connect_async()

migrated from Bugzilla #484733
status UNCONFIRMED severity major in component MQTT-Python for 1.2
Reported in version 1.1 on platform PC
Assigned to: Roger Light

On 2015-12-20 12:06:18 -0500, Jake Callery wrote:

Seems as thought client.connect() simply calls client.connect_async(). This goes against what the docs claim. connect() should be a blocking call. Since it seems to be not, trying to subscribe (like many of the examples out there show) right after a connect call will fail because the connection has not been established before the call to subscribe.

Docs:
https://pypi.python.org/pypi/paho-mqtt#connect-reconnect-disconnect
"The connect() function connects the client to a broker. This is a blocking function. It takes the following arguments:"

Code:
def connect(self, host, port=1883, keepalive=60, bind_address=""):
"""Connect to a remote broker.

    host is the hostname or IP address of the remote broker.
    port is the network port of the server host to connect to. Defaults to
    1883. Note that the default port for MQTT over SSL/TLS is 8883 so if you
    are using tls_set() the port may need providing.
    keepalive: Maximum period in seconds between communications with the
    broker. If no other messages are being exchanged, this controls the
    rate at which the client will send ping messages to the broker.
    """
    self.connect_async(host, port, keepalive, bind_address)
    return self.reconnect()

Add External Event Loop Example

Hi,
i'd like to use this library together with the twisted reactor. Since i'm new to both paho.mqtt and twisted its hard for me to figure this one out. It would be nice to have an example of the external event loop usage (mustn't be twisted).

callback is not called anymore after server received a HUP signal

migrated from Bugzilla #478344
status CLOSED severity normal in component MQTT-Python for 1.2
Reported in version 1.1 on platform PC
Assigned to: Roger Light

On 2015-09-24 15:22:25 -0400, Kees Bakker wrote:

The callback is not called anymore after the MQTT server did get an HUP signal. (It gets the HUP signal as part of logrotate on Ubuntu)

Consider this little program to show the problem.

import sys
import paho.mqtt.client as mqtt

def on_message(mosq, obj, msg):
print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
sys.stdout.flush()

def main():
mqttc = mqtt.Client()

mqttc.on_message = on_message
mqttc.connect("localhost")
mqttc.subscribe("TPHUNBBEE/device/#", 0)

mqttc.loop_forever()

main()

It prints the message it is subscribed to. The actual script runs forever, as the loop_forever suggests. But everytime the MQTT server (I'm using mosquitto) gets a HUP signal the script stops getting callbacks. I have to kill it and restart.

On 2015-09-24 18:47:06 -0400, Roger Light wrote:

The problem is because you are not a durable client (clean_session is set to True by default) and you only subscribe at the start of your program. If your client is ever disconnected, it will reconnect but not resubscribe.

Try putting the subscribe() call in your on_connect() callback.

On 2015-09-25 15:03:42 -0400, Kees Bakker wrote:

Ah, I see. Sorry for the noise then. Indeed it works as you describe. It even is in the README.rst (which I probably never did).

Thanks for responding so quickly

On 2015-09-25 16:11:39 -0400, Roger Light wrote:

No problem, I'm happy to help.

Unable to determine version number at runtime

migrated from Bugzilla #435112
status RESOLVED severity enhancement in component MQTT-Python for 0.9
Reported in version unspecified on platform All
Assigned to: Roger Light

On 2014-05-17 03:43:48 -0400, Christian Clauss wrote:

Enhancement request: add .VERSION attribute to the Paho MQTT-Python module to enable detecting software version number at runtime.

$ python

import paho
paho.VERSION
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'module' object has no attribute 'VERSION'

On 2014-05-29 16:20:19 -0400, Roger Light wrote:

Thanks for the report. After a bit of thought, I've added the version information to paho.mqtt.version. I think this is more appropriate than paho.version.

http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/commit/?id=SHA: 525e684

Reconnect on an SSL socket can block forever

migrated from Bugzilla #478959
status UNCONFIRMED severity major in component MQTT-Python for 1.2
Reported in version unspecified on platform PC
Assigned to: Roger Light

Original attachment names and IDs:

On 2015-10-03 13:25:52 -0400, Jeff Jasper wrote:

Created attachment 257015
Patch for the bug.

The ssl.wrap_socket call within the reconnect method can block forever if the broker (for whatever reason) does not respond during the handshake. I don't know what's causing the broker (RabbitMQ) to not respond but it occurs occasionally and happens more frequently under network conditions with high latencies.

I'm including a patch where I perform the TLS handshake after wrapping the socket and give the socket a 10 second timeout. After the handshake completes I set the socket to non-blocking. Feel free to change my hard coded 10 sec. block to something more configurable.

Also included in the patch is a broad exception catch to release the _current_out_packet_mutex to avoid potential deadlock (I've never experienced this but noticed it when I was troubleshooting the previous issue).

On 2016-01-04 19:04:49 -0500, Adam mills wrote:

We are seeing this as well with Mosquitto as a broker.

Websocket support for paho python

migrated from Bugzilla #482282
status UNCONFIRMED severity normal in component MQTT-Python for 1.2
Reported in version 1.1 on platform All
Assigned to: Roger Light

Original attachment names and IDs:

On 2015-11-16 08:02:45 -0500, Milan Toth wrote:

Created attachment 257966
weboscket support git patch

Websocket support patch for paho python

Python 3 issue: client.publish does not accept bytes payload as returned by struct.pack

migrated from Bugzilla #486185
status UNCONFIRMED severity normal in component MQTT-Python for 1.2
Reported in version 1.1 on platform All
Assigned to: Roger Light

On 2016-01-20 11:12:07 -0500, Andreas Koehler wrote:

The documentation suggests using struct.pack() to create payloads.

But invoking e.g. client.publish("test",struct.pack('>d',1.2345)) results in an error:

File "D:\Miniconda3\envs\python34\lib\site-packages\paho\mqtt\client.py", line 871, in publish
raise TypeError('payload must be a string, bytearray, int, float or None.')

This is because client.publish only checks isinstance(payload, bytearray), but not isinstance(payload, bytes), which is what struct.pack returns on Python 3

Easy fix in client.py on line 864: for sys.version_info[0]==3 use isinstance(payload, bytes) instead of isinstance(payload, unicode)

Workaround: use bytearray(struct.pack(...)) to create payload.

On 2016-01-20 11:18:54 -0500, Andreas Koehler wrote:

Regarding the fix - it's not only line 864... there are more type checks on the payload later on...

Does changing the system datetime affect or stop Paho MQTT Client in asynchronous mode?

I am using the Paho MQTT Client in asynchronous mode on a raspberry pi. The program sometimes stops sending MQTT messages and it happens not very often. When looking in the syslog I noticed that when this happens there is also a bug that the system datetime flashed back one day or a few minutes. Can this affect or stop Paho MQTT Client in asynchronous mode?

Exception: Resource temporarily unavailable

migrated from Bugzilla #430850
status RESOLVED severity major in component MQTT-Python for ---
Reported in version v0.5 on platform PC
Assigned to: Roger Light

On 2014-03-20 23:47:14 -0400, Roy Barkas wrote:

I'm running the paho python client connecting to a Hivemq server.
All messages are sent with QOS=0.
Typical message size is 100 bytes.
Traffic is approx 130 messages per second.

Everything works fine for a while and then the following exception occurs. Once this exception has occurred, no further messages are seen on the topic and
on_publish() is not activated.

The client.publish() returns 0 in every case.

My best guess (and that's all it is) is that the socket buffer get's full, does something, and then the client doesn't recover from the problem.

I've worked around this by coding a deadman timer that is reset by each activation of the on_publish method.

But it would be a lot better to identify and fix the root cause.

Anything I can do on my end to fix it?

Exception that is seen:

Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 808, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 761, in run
self.__target(_self.__args, *_self.__kwargs)
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 2091, in _thread_main
self.loop_forever()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 1188, in loop_forever
rc = self.loop(timeout, max_packets)
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 790, in loop
self._sockpairR.recv(1)
error: [Errno 11] Resource temporarily unavailable

On 2014-03-21 01:59:27 -0400, Roy Barkas wrote:

The client in question is accessed from a number of places in a multi-threaded module.

As a temporary measure I've set up a separate client within the module for the high-traffic section. Will report on results.

On 2014-03-21 04:53:02 -0400, Roger Light wrote:

Thanks for the report. I think this was already fixed in this commit:

http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/commit/?id=SHA: 2f41069

Could you try updating your client? That version should already be on pypi.

On 2014-04-16 16:10:01 -0400, Roger Light wrote:

I believe this is already fixed in a later version of the code than you were using. If you still have a problem please reopen the bug.

Publish module - function single() ignores parameter 'protocol'

migrated from Bugzilla #438484
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version v0.5 on platform Other
Assigned to: Roger Light

On 2014-06-29 06:37:34 -0400, Franis Sirkovic wrote:

Finction single() in publish module does not pass parameter protocol to function multiple(). So, multiple() uses default version of the protocol MQTTV311. So, it is impossible to use brokers that support just older versions (RabbitMQ - MQTTv31).

On 2014-09-12 17:14:12 -0400, Roger Light wrote:

This is fixed in the repository, thanks for the report.

Disconnect hangs on loop_forever() not returning in paho.mqtt.publish.multiple

migrated from Bugzilla #436615
status RESOLVED severity normal in component MQTT-Python for 0.9
Reported in version 0.9 on platform PC
Assigned to: Roger Light

Original attachment names and IDs:

On 2014-06-04 13:33:49 -0400, Ruben van Staveren wrote:

Created attachment 243949
Patch against 0.9.1. partly duplicates 436379

Using this simple program keeps the client waiting forever as _packet_write cannot escape the loop when write_length is zero.

Attached is a diff that more or less duplicates the clearing out of self._current_out_packet. Not sure if the mutexes are required when write_length is zero.

Note that since this diff is against 0.9.1 it also includes a fix mentioned in 436379

! /usr/bin/env python

import paho.mqtt.publish as publish
import ssl

try:
publish.multiple(
[
{'topic':"topic/test", 'payload':"test123"},
{'topic':"topic/test", 'payload':"test456"},
{'topic':"topic/test", 'payload':"test789"},
],
hostname="server.example.com",
port=8883,
will={'topic':"topic/status", 'payload':"Unexpected EOF"},
tls={
'ca_certs': "ca.crt",
'certfile': "client.crt",
'keyfile': "client.key",
'tls_version': ssl.PROTOCOL_TLSv1
})
except ssl.SSLError as e:
print e

On 2014-06-04 17:00:36 -0400, Roger Light wrote:

Thanks for the report, I've pushed a fix for it.

Possible SSL data leak on publish

migrated from Bugzilla #443964
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version future on platform PC
Assigned to: Roger Light

On 2014-09-12 11:15:47 -0400, Hiram van Paassen wrote:

It is possible when using SSL to send data unencrypted

self._sock is created before self._ssl. A publish which is sent in between is sent unencrypted and messes up the ssl handshake. Depending on the exact place in the handshake this can trick the client in sending some more unencrypted publishes before giving up

Possible solution:
assign self._sock only after self._ssl is assigned. Store the reference untill then in a temporary variable (in reconnect() )

On 2014-09-12 17:11:33 -0400, Roger Light wrote:

Thanks, this is a very good find.

I've pushed a commit that should fix it.

mqtt client flash without network

migrated from Bugzilla #476694
status UNCONFIRMED severity critical in component MQTT-Python for 1.2
Reported in version 1.1 on platform PC
Assigned to: Roger Light

On 2015-09-05 06:19:59 -0400, Paolo Patruno wrote:

mqtt client stop for ever if only local interface is up in network configuration.

program stop inside sock1.connect(("127.0.0.1", port)) in _socketpair_compat

On 2015-09-07 10:01:07 -0400, Paolo Patruno wrote:

Solved with:
sock1.settimeout(10)

....
sock2.settimeout(10)

Client.subscribe() fails for unicode topic

migrated from Bugzilla #462379
status UNCONFIRMED severity normal in component MQTT-Python for 1.1
Reported in version unspecified on platform Macintosh
Assigned to: Roger Light

On 2015-03-17 11:13:50 -0400, Michael Laing wrote:

If the topic arg is unicode, subscribe() considers it invalid.

This is because tests in the method are for 'str' and not 'basestring'.

The documentation for the method should be correspondingly updated.

The workaround is to encode the topic arg as utf8 before sending to the method.

On 2015-03-17 19:35:42 -0400, Roger Light wrote:

Is this on Python 2.x?

allow Client Identifier to be a nullstring

Why using no client_id isn't authorized ? It's sometime useful, and this is allowed by MQTT specifications :

A Server MAY allow a Client to supply a ClientId that has a length of zero bytes, however if it does so the Server MUST treat this as a special case and assign a unique ClientId to that Client. It MUST then process the CONNECT packet as if the Client had provided that unique ClientId [MQTT-3.1.3-6].

If the Client supplies a zero-byte ClientId, the Client MUST also set CleanSession to 1 [MQTT-3.1.3-7].


Also, current implementation of random ClientId is not very safe, because it can lead to subtle bugs. For instance, this script causes mqtt.Client chooses the same ClientId for clients, introducing competition between them to take over if we run several clients :

import random
import paho.mqtt.client as mqtt


def on_connect(client, userdata, flags, rc):
    print(client._client_id, "Connected with result code ", rc)

def on_disconnect(client, userdata, rc):
    print(client._client_id, "Disconnected with result code ", rc)


# suppose, for some reason, we make
random.seed(0)

# and just later start the client
client = mqtt.Client()
client.on_connect = on_connect
client.on_disconnect = on_disconnect

client.connect("iot.eclipse.org")
client.loop_forever()

loop_stop can run before _thread_main

migrated from Bugzilla #448428
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version v0.5 on platform PC
Assigned to: Roger Light

On 2014-10-22 17:09:07 -0400, Kees Bakker wrote:

Hi,

Consider this little example

import paho.mqtt.client as mqtt

mqttc = mqtt.Client()
mqttc.username_pw_set('user', 'password')
mqttc.connect('ftp.mydomain.com')
mqttc.loop_start()

mqttc.publish("SODAQ/rainstation/16c28153/rain1", '0', retain=True)

mqttc.loop_stop()

On some Linux systems (not all) it hangs.

With simple debugging (adding print statements) I found out that in that case Client.loop_stop runs before(!) Client._thread_main.

And when that happens _thread_terminate is first made True, and then False again before the while loop in loop_forever gets a chance to terminate.

A workaround is to insert a sleep between loop_start and loop_stop

On 2014-10-22 17:45:41 -0400, Roger Light wrote:

Thanks, that's interesting.

I'm not disputing the central point of your report, but would just like to point out that what you're doing isn't really the best way of using the API. I'd use loop_forever(), then call disconnect() in the on_publish() callback.

Or just use paho.mqtt.publish.single().

I'll see what the best approach for fixing this is though.

On 2014-10-22 18:36:20 -0400, Roger Light wrote:

I haven't managed to reproduce it yet myself. Does this do the trick?

diff --git a/src/paho/mqtt/client.py b/src/paho/mqtt/client.py
index b662aeb..46d0833 100755
--- a/src/paho/mqtt/client.py
+++ b/src/paho/mqtt/client.py
@@ -1282,6 +1282,7 @@ class Client(object):
if self._thread is not None:
return MQTT_ERR_INVAL

  •    self._thread_terminate = False
     self._thread = threading.Thread(target=self._thread_main)
     self._thread.daemon = True
     self._thread.start()
    

    @@ -2247,8 +2248,6 @@ class Client(object):
    self._callback_mutex.release()

    def _thread_main(self):

  •    run = True
    
  •    self._thread_terminate = False
     self._state_mutex.acquire()
     if self._state == mqtt_cs_connect_async:
         self._state_mutex.release()
    

On 2014-10-23 03:43:44 -0400, Kees Bakker wrote:

(In reply to Roger Light from comment # 1)

Thanks, that's interesting.

I'm not disputing the central point of your report, but would just like to
point out that what you're doing isn't really the best way of using the API.
I'd use loop_forever(), then call disconnect() in the on_publish() callback.

Or just use paho.mqtt.publish.single().

I'll see what the best approach for fixing this is though.

He, I'm not at all surprised that you say this :-) This is what happens when someone new starts using the software.

I was just trying to figure out what to do. For me, the reason not to use publish.single() was that I have about 10-15 topics that I want to publish to. It seems a waste to repeately open the connection, send a message, and close. I could (should?) use publish.multiple().

But then again, you would never have known about this problem, now would you?

On 2014-10-23 04:17:33 -0400, Kees Bakker wrote:

(In reply to Roger Light from comment # 2)

I haven't managed to reproduce it yet myself. Does this do the trick?

diff --git a/src/paho/mqtt/client.py b/src/paho/mqtt/client.py
index b662aeb..46d0833 100755
--- a/src/paho/mqtt/client.py
+++ b/src/paho/mqtt/client.py
@@ -1282,6 +1282,7 @@ class Client(object):
if self._thread is not None:
return MQTT_ERR_INVAL

  •    self._thread_terminate = False
     self._thread = threading.Thread(target=self._thread_main)
     self._thread.daemon = True
     self._thread.start()
    

    @@ -2247,8 +2248,6 @@ class Client(object):
    self._callback_mutex.release()

    def _thread_main(self):

  •    run = True
    
  •    self._thread_terminate = False
     self._state_mutex.acquire()
     if self._state == mqtt_cs_connect_async:
         self._state_mutex.release()
    

Yes, that does the trick. Thanks.

What are your plans with PyPi? How is that handled? At the moment it still has 1.0

On 2014-11-01 14:12:51 -0400, Roger Light wrote:

I've committed the change now.

To be honest I'm a bit confused about pypi - I thought I'd pushed the 1.0.x releases but they certainly aren't there. I'll make sure it's sorted once I release 1.0.3.

Client.publish() fails if payload arg is <str> type and contains a byte not in range(128); python 2.7

migrated from Bugzilla #462441
status UNCONFIRMED severity normal in component MQTT-Python for 1.1
Reported in version unspecified on platform Macintosh
Assigned to: Roger Light

On 2015-03-18 05:01:50 -0400, Michael Laing wrote:

Python 2.7 s may contain 8-bit bytes.

If a containing a byte outside of range(128) is passed as the payload arg to Client.publish(), an error like the following occurs:

UnicodeDecodeError: 'ascii' codec can't decode byte in position : ordinal not in range(128)

Probably the best solution is to guard the encode in this part of the method with a try clause.

The workaround is to always pass in the payload as or , avoiding , particularly if the payload is opaque in one's application.

Unclear error message when bad authentication with paho.mqtt.publish

migrated from Bugzilla #481229
status UNCONFIRMED severity minor in component MQTT-Python for 1.2
Reported in version unspecified on platform PC
Assigned to: Roger Light

On 2015-11-02 06:00:58 -0500, Pierre Fersing wrote:

When using paho.mqtt.publish (single or multiple) with an MQTT broker requiring authentication and providing wrong (or no) credentials, the error is unclear:

paho.mqtt.publish.single('topic', 'msg', hostname='localhost', auth={'username':"user", 'password':"WRONG password"})
Traceback (most recent call last):
File "", line 1, in
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/publish.py", line 216, in single
multiple([msg], hostname, port, client_id, keepalive, will, auth, tls, protocol)
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/publish.py", line 170, in multiple
client.loop_forever()
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/client.py", line 1261, in loop_forever
rc = self.loop(timeout, max_packets)
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/client.py", line 811, in loop
rc = self.loop_read(max_packets)
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/client.py", line 1073, in loop_read
rc = self._packet_read()
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/client.py", line 1475, in _packet_read
rc = self._packet_handle()
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/client.py", line 1949, in _packet_handle
return self._handle_connack()
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/client.py", line 2010, in _handle_connack
self.on_connect(self, self._userdata, flags_dict, result)
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/publish.py", line 53, in _on_connect
_do_publish(c)
File "/home/pierref/.virtualenvs/paho/local/lib/python2.7/site-packages/paho/mqtt/publish.py", line 27, in _do_publish
m = c._userdata[0]
IndexError: list index out of range

From what I understand, this issue is in publish.py:_on_connect function:

def _on_connect(c, userdata, flags, rc):
"""Internal callback"""
_do_publish(c) <-- here it try to publish ALWAYS, including when rc != 0

With bad credential, rc == 4 ("Connection refused - bad username or password").
It should probably be better to raise exception when rc != 0 (at least for wrong password/client id, since retrying won't change the outcome).

Cannot connect with python client (1.0 and 1.1): "[Errno 54] Connection reset by peer"

migrated from Bugzilla #451735
status RESOLVED severity major in component MQTT-Python for 1.1
Reported in version 1.1 on platform Macintosh
Assigned to: Roger Light

On 2014-11-16 10:10:35 -0500, Marcel M wrote:

This error is generated in mqttc.loop_forever().

The server address is correct (verified with other clients).
I tried the default version from pipit and 1.0 and 1.1 from git. The retry_first_connection parameter in v1.1 looked promising but didn't help.
Using python 2.7.8.

This is the program, adapted from an example:

import paho.mqtt.client as mqtt

def on_connect(mqttc, obj, flags, rc):
print("rc: "+str(rc))

def on_message(mqttc, obj, msg):
print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))

def on_publish(mqttc, obj, mid):
print("mid: "+str(mid))

def on_subscribe(mqttc, obj, mid, granted_qos):
print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_log(mqttc, obj, level, string):
print(string)

If you want to use a specific client id, use

mqttc = mqtt.Client("client-id")

but note that the client id must be unique on the broker. Leaving the client

id parameter empty will generate a random id for you.

mqttc = mqtt.Client()
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe

Uncomment to enable debug messages

mqttc.on_log = on_log
mqttc.connect("192.168.2.201", 1883, 60)

mqttc.subscribe("$SYS/#", 0)

mqttc.subscribe("outTopic", 0)

mqttc.loop_forever(retry_first_connection=True) # # for version 1.1

mqttc.loop_forever() # for version 1.0

On 2014-11-16 10:18:39 -0500, Marcel M wrote:

Found a solution/workaround: adding the protocol to the client instantiation makes it work.

mqttc = mqtt.Client(protocol=mqtt.MQTTv31)

(note that mqtt.MQTTv311 gives the error, mqtt.MQTTv31 does not).

Maybe not a bug but confusing for the user. None of the other clients I tried (MQTT lens, mosquitto-sub) required me to specify the protocol.

It would be helpful to stress the importance of this 'optional' param in the docs.

On 2015-01-12 19:39:19 -0500, Roger Light wrote:

I have reverted the default behaviour to use v3.1 when connecting. The essential problem is that server implementations that don't support v3.1.1 often don't return the correct CONNACK code when an invalid protocol version is sent to them, so the automatic protocol fallback doesn't work.

On 2015-01-12 19:43:12 -0500, Roger Light wrote:

*** Bug 446062 has been marked as a duplicate of this bug. ***

SSL wrapped socket is not set to non-blocking

migrated from Bugzilla #465625
status UNCONFIRMED severity normal in component MQTT-Python for 1.1
Reported in version 1.1 on platform PC
Assigned to: Roger Light

Original attachment names and IDs:

On 2015-04-27 16:13:31 -0400, Jeff Jasper wrote:

When using SSL enabled Paho and publishing a large number (~ 1000) of messages in rapid succession I noticed a behavior where 50-100 messages would be sent and then a period of 1 minute would elapse before the remaining messages were sent. I tracked the delay down to the ssl.read(1) (line 1405) method in _packet_read. It appears that the socket may be getting disconnected causing the read to block for a minute before returning an empty byte.

I noticed that the ssl wrapped socket (generated in the reconnect method) is not explicitly set to non-blocking like it is for a non-SSL socket. After setting the ssl wrapped socket to non-blocking the delay when publishing a large burst of messages appears to be gone. I guess this isn't necessarily a bug, but rather a performance issue.

On 2015-05-23 17:21:11 -0400, Roger Light wrote:

Hi Jeff,

Thanks for this, but I'm a bit confused. The socket gets set to be non-blocking around line 756, regardless of whether it is SSL or not. The ssl.wrap_socket() call is blocking, but everything afterwards should be non-blocking.

On 2016-01-12 05:21:16 -0500, Pierre Fersing wrote:

Created attachment 259120
script to test SSL blocking status

I confirm what Jeff seen, SSL is blocking... but only with Python 3 :(

Python 2 works well, but not Python 3 (tested 2.7.10 and 3.4.3)

With Python 2 calling setblocking(0) on either raw-socket or ssl-socket is enough.

With Python 3 calling setblocking(0) on raw-socket change nothing on ssl-socket. We need to call setblocking(0) on ssl-socket to make ssl socket non-blocking.

I've attached a basic script that I used to test the blocking status of ssl socket.

Invoking will_set does not register LWT with RabbitMQ v3.3.0

migrated from Bugzilla #444770
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version 1.0 on platform PC
Assigned to: Roger Light

On 2014-09-22 14:02:59 -0400, Jeff Jasper wrote:

This feature works in pre 1.0 and my guess is that the explicit encoding modification contributes to this. I have not tested it with any other broker.

On 2015-01-31 20:36:08 -0500, Roger Light wrote:

I believe this is a bug in rabbitmq. There is a discussion about what I believe to be the same problem here: https://groups.google.com/forum/#!topic/rabbitmq-users/Co7HFORA1qc

I'm marking this bug as "not eclipse", because I think the bug is in rabbitmq. If you think this is still a bug with Paho Python, please reopen the bug.

ssl certificates are not parsed correctly

migrated from Bugzilla #436379
status RESOLVED severity normal in component MQTT-Python for 0.9
Reported in version 0.9 on platform PC
Assigned to: Roger Light

On 2014-06-02 11:30:33 -0400, Hiram van Paassen wrote:

Here is a patch to allow the GoDaddy root cert (as is included by firefox etc) to be used with the paho python client using ssl

https://git.eclipse.org/r/#/c/24855/

On 2014-06-03 12:15:05 -0400, Roger Light wrote:

I agree, this looks like a copy-paste error.

I don't believe that this is anything to do with CA certificates though, the check that you have modified is purely for host certificates that have the subjectAltName field.

If you update the commit message I'll be very happy to accept the change. It's the first submission I've had over gerrit though, so I need to check that I do everything correctly for IP etc., which might delay me slightly.

On 2014-06-04 02:24:00 -0400, Hiram van Paassen wrote:

Changed commit and rebased to latest version.

On 2014-06-04 02:26:01 -0400, Hiram van Paassen wrote:

If there are some hassles regarding IP etc. Feel free to apply your own fix to the same effect ;-)

On 2014-06-04 17:17:47 -0400, Roger Light wrote:

Does the email you used in the commit match the one that you signed the Eclipse CLA with?

On 2014-06-06 07:16:06 -0400, Hiram van Paassen wrote:

Not sure i think the one from the commit message. I cannot find with which email I signed. But both email addresses are linked to my account and gerrit accepts my pushes saying I have signed a CLA

On 2014-06-06 23:29:04 -0400, Roger Light wrote:

Ok great, that should be fine then.

There's only one other thing, and that is to include

Bug: 436379

in the commit message footer. I should've spotted that before, sorry. Like I said, you're a bit of a guinea pig for me here :)

On 2014-06-07 11:52:04 -0400, Hiram van Paassen wrote:

Sure, done

On 2014-06-07 16:05:09 -0400, Roger Light wrote:

I've approved and merged your patch, thanks for your patience!

on_connect() argument call

When launching a client, the following error shows up (sometimes):

Traceback (most recent call last):
File "simple_client.py", line 29, in
client.run()
File "simple_client.py", line 13, in run
self.client.loop()
File "/Library/Python/2.7/site-packages/paho/mqtt/client.py", line 811, in loop
rc = self.loop_read(max_packets)
File "/Library/Python/2.7/site-packages/paho/mqtt/client.py", line 1073, in loop_read
rc = self._packet_read()
File "/Library/Python/2.7/site-packages/paho/mqtt/client.py", line 1475, in _packet_read
rc = self._packet_handle()
File "/Library/Python/2.7/site-packages/paho/mqtt/client.py", line 1949, in _packet_handle
return self._handle_connack()
File "/Library/Python/2.7/site-packages/paho/mqtt/client.py", line 2010, in _handle_connack
self.on_connect(self, self._userdata, flags_dict, result)
TypeError: on_connect() takes exactly 4 arguments (5 given)

Looking into the source code and the following chunk (line 2005 in /src/paho/mqtt/client.py):

if argcount == 3:
self.on_connect(self, self._userdata, result)
else:
flags_dict = dict()
flags_dict['session present'] = flags & 0x01
self.on_connect(self, self._userdata, flags_dict, result)

Making a self. call inside of a python class adds an additional argument to the function call, effectively making it 4 arguments, not 3. Another suggestion is that the else command should probably be an elif considering any other number of arguments that are not 4 or 5 should produce an error.

Ssl lost connection results in non functional connection

migrated from Bugzilla #436463
status UNCONFIRMED severity normal in component MQTT-Python for 0.9
Reported in version 0.9 on platform PC
Assigned to: Roger Light

On 2014-06-03 10:39:43 -0400, Hiram van Paassen wrote:

We use a script to subscribe a power supply to mqtt over ssl. We notice that sometimes the network connection is not stable and the script looses its connection. It should try to reconnect because we use loop_start() (same behavior with loop_forever()) but it fails to make a proper connection.

I noticed that in a previous version the ssl.read(1) call in loop_read() would sometimes "read" 0 bytes when this happens

Unfortunately I have not been able to find the real source or to create better logging but here is some logging from our script to show what happens:

The source of published messages is guaranteed to publish every 5 seconds even after the network failure

$ ./start_script.py
Checking watchdogs
Connection Accepted.
subscribed
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
Got published message
Checking watchdogs
[Errno 104] Connection reset by peer
Checking watchdogs
Checking watchdogs
Connection Accepted.
Connection Accepted.
Checking watchdogs
Connection Accepted.
Checking watchdogs
Connection Accepted.
Connection Accepted.
Checking watchdogs
Connection Accepted.
Checking watchdogs
Connection Accepted.
Checking watchdogs
Checking watchdogs
Connection Accepted.

relevant code:

def on_message(mosq, userdata, mqtt_message):
print "Got published message"

def on_connect(mosq, userdata, rc):
print mosquitto.connack_string(rc)
# subscribe to commands
mqtt.subscribe(COMMAND_TOPIC, 2)

def on_subscribe(mosq, userdata, mid, granted_qos):
print "subscribed"

mqtt = mosquitto.Client(clean_session=True)
mqtt.tls_set(CERT_DIR)
mqtt.username_pw_set("user", "password")

set message callback

mqtt.on_message = on_message
mqtt.on_connect = on_connect
mqtt.on_subscribe = on_subscribe

keepalive of 50 seconds

because loadbalancer loses connection after 60 seconds of inactivity

mqtt.connect(MQTT_HOSTNAME, 8883, 50)

mqtt.loop_start()

I would expect to see the script reconnect and to start receiving published messages again. This regardless of clean_session=True btw.

On 2014-06-17 04:12:04 -0400, Roger Light wrote:

I wonder if the fix used for bug # 436615 fixes this for you as well. Would you be able to try the latest code from the repository please?

On 2014-09-12 17:22:12 -0400, Roger Light wrote:

Could this be related to the other bugs you've filed? It feels like it could be.

Lost connection results in unrecoverable state (both SSL and non SSL)

migrated from Bugzilla #443881
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version 1.0 on platform PC
Assigned to: Roger Light

On 2014-09-11 17:44:12 -0400, Jeff Jasper wrote:

I am using the client (checked out from 5605f91) in a fashion where I invoke loop_start. The network environment is an environment where the internet connection is unstable and occasionally the connection will drop long enough to trigger the disconnect callback. Messages continue to be published to the client during this period. Shortly after the internet connection is re-established a ValueError with the message "file descriptor cannot be a negative integer (-1)" is encountered in the loop method:
socklist = select.select(rlist, wlist, [], timeout) (line 787)
The rlist and wlist argument fd fields are both disconnected with values of -1.

Currently the previous statement is invoked with the catch being a TypeError. Since it's uncaught the client never reconnects and publishes subsequent messages. If I add the proper catch the client will reconnect and then go back into a functional state.

Let me know if anymore detail is needed and try and provide what I can.

On 2014-09-12 17:54:25 -0400, Roger Light wrote:

Thanks for the report.

It feels like returning MQTT_ERR_CONN_LOST or MQTT_ERR_NO_CONN is the correct choice after the catch, but this might trigger another reconnection attempt - it's not entirely clear to me from your description whether this is required.

Are you returning an error or success after the catch? Tell me that and then it's a pretty easy fix.

On 2014-09-13 12:56:01 -0400, Jeff Jasper wrote:

Since the socket appears to be disconnected a reconnect is required so I continue to have the method return MQTT_ERR_CONN_LOST. For now I've modified the code as follows:

    try:
        socklist = select.select(rlist, wlist, [], timeout)
    except Exception as ex:
        template = "An exception of type {0} occured. Arguments:\n{1!r}"
        message = template.format(type(ex).__name__, ex.args)
        logging.debug(message)
        # Socket isn't correct type, in likelihood connection is lost
        return MQTT_ERR_CONN_LOST

On 2014-09-13 16:24:46 -0400, Roger Light wrote:

Thanks, I've pushed a commit to fix this.

Callbacks definition and inheritance

Hi guys,

I'm using the Python implementation of MQTT through the paho-mqtt package. The documentation says that you can inherit from the Client class to create your own MQTT_client. Nevertheless, inheriting from the client doesn't allow you to define some on_* functions directly in the class because they are overridden by the init call of the base class...

So, there is any particular reason the define Client.on_* to None in the init instead of using classical member functions like this :

class Client(object):
    def __init__(self, ...):
        ...
        # Nothing about self.on_*

    def on_*(self, ...):
        pass

An implementation like this would not break the actual behavior (you can redefine the functions, using mqttc.on_connect = my_new_connect_function), and it would be easier to inherit, defining overriding on_* functions in the sub-class.

If this seems a good idea, I propose myself to do the patch.

Kind regards,
Alexis BRENON

Paho/Python Readme file update

migrated from Bugzilla #431228
status RESOLVED severity normal in component MQTT-Python for ---
Reported in version v0.5 on platform All
Assigned to: Roger Light

Original attachment names and IDs:

On 2014-03-26 08:15:35 -0400, Oscar Franco wrote:

Created attachment 241267
Updated readme file with basic information on the use of the library

Hello, my name is Oscar Franco.

I work for CodeRoad, we are a software company teamed up with several IoT partners, one of our partners Xively has asked us to go through the documentation of several libraries as some of them doesn't seem to be complete and/or accurate, my responsability is to update the paho-mqtt library documentation.

Although the current python library has a complete documentation inside the code via pydocs, the Readme file is far more easy to see while browsing for libraries to use the MQTT protocol, with this motiv I have a attached a updated version of the "Readme.md" file for the committers of the project to review and update.

Many thanks!

On 2014-04-16 16:45:22 -0400, Roger Light wrote:

Thanks for this, I'm not entirely sure how to deal with the contribution properly.

This is mostly because it needs some modifications - a quick example is that MQTT should not be expanded any more. I can make the modifications I want but it complicates the contribution.

On 2014-04-17 08:27:06 -0400, Oscar Franco wrote:

It's okay if you have to make some modifications to the file, you may proceed as you wish.

(In reply to Roger Light from comment # 1)

Thanks for this, I'm not entirely sure how to deal with the contribution
properly.

This is mostly because it needs some modifications - a quick example is that
MQTT should not be expanded any more. I can make the modifications I want
but it complicates the contribution.

On 2014-04-22 13:18:51 -0400, Roger Light wrote:

I've just pushed a commit that documents the whole of the client and publish modules.

http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/commit/?id=SHA: 8c01e63

I've not included any information on MQTT itself because the document is already quite long.

I would consider the bug resolved and have marked it as such, but if you disagree please reopen the bug.

connect_async() doesn't work with all the loop*() functions as mentioned in docs, it can only work with some. For me it didn't work with any.

As mentioned in the docs:

Identical to connect(), but non-blocking. The connection will not complete until one of the loop*() functions is called.

But it cannot work with simple loop(), because, calling connect_async() doesn't actually create the connection, rather it just initiates some private variables.

Unlike connect(), which calls connect_async() to initialise those private variable followed by reconnect() which actually creates the socket connection, thus by simply calling connect_async() it doesn't create the connection since its not calling reconnect() directly in its method.

Moreover, if you are calling just connect_async(), you can only call some selected loop*() functions, specifically those which in return go ahead and calls reconnect(), hence, those are loop_forever() and loop_start().

Also, given these conditions, I did try connect_async() with both loop_forever() and loop_start() but both seemed to got stuck and not reply with any messages (even after subscribing to $SYS/# topics).

connect() and connect_async() is not having a proper difference as mentioned in the docs.

From the docs, there are 3 methods to connect:

  1. connect()
  2. connect_async()
  3. connect_srv()

It says the

Identical to connect(), but non-blocking. The connection will not complete until one of the loop*() functions is called.

But actually, connect() calls connect_async() first and then calls reconnect(). Thus saying connect() and connect_async working differently is not that proper. Moreover, connect() being blocking and connect_async() being non-blocking is not correct as both of them end up doing the same thing (just that with connect_async(), few things have to be taken care of).

Its been referred already in #4

MQTT 3.1.1 support for Python client

migrated from Bugzilla #434143
status RESOLVED severity normal in component MQTT-Python for 1.0
Reported in version 1.0 on platform PC
Assigned to: Roger Light

On 2014-05-05 15:45:36 -0400, Roger Light wrote:

  1. By default a client library will try to connect with MQTT 3.1.1, and if this fails, try again with MQTT 3.1. This will allow existing applications to work with new servers, unchanged.
  2. A new connect option which allows the application to specify 3.1.1 or 3.1 only.

On 2014-05-05 15:46:58 -0400, Roger Light wrote:

Blocks 433833.

On 2014-05-12 17:40:23 -0400, Roger Light wrote:

This behaviour is now implemented in the 1.0 branch.

http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/log/?h=1.0

The choice of protocol is set when creating the client not when connecting.

On 2014-05-31 04:52:18 -0400, Roger Light wrote:

Reopening because "session present" not currently supported in on_connect callback.

On 2014-06-12 05:36:31 -0400, Ian Craggs wrote:

Roger,

  1. are you able to add the session present flag update for a 1.0 release on the 25th June?

  2. is that support also in Mosquitto? I've added it to the test MQTT server in org.eclipse.paho.testing. I was thinking of running a copy of the test server on iot.eclipse.org because we can configure that to behave erroneously if we want to, for the purposes of testing the clients.

On 2014-06-20 18:00:22 -0400, Roger Light wrote:

Resolved in this commit: http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/commit/?id=SHA: 713955b

Wildcard certificates (TLS) are not supported

migrated from Bugzilla #440547
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version 1.0 on platform All
Assigned to: Roger Light

On 2014-07-28 09:16:15 -0400, Juan Carlos Jimenez wrote:

The library compares the field "commonName" with the URL provided. If you are using a wildcard certificate, the addresses won't match and the user gets a "raise ssl.SSLError('Certificate subject does not match remote hostname.')"

The code can be found in the function _tls_match_hostname, in src/paho/mqtt/client.py :

    subject = cert.get('subject')
    if subject:
        for ((key, value),) in subject:
            if key == 'commonName':
                if value.lower() == self._host.lower():
                    return

    raise ssl.SSLError('Certificate subject does not match remote hostname.')

On 2014-07-28 09:28:28 -0400, Roger Light wrote:

Agreed, this is the case. I've had some code contributed elsewhere to fix this, hopefully I can get that merged in.

On 2014-08-26 09:51:38 -0400, Calum Barnes wrote:

Any progress on this issue? It is also preventing me from using TLS due my brokers cert. It works fine in Python3 where you are using the ssl lib to check the hostname. Any reason this cant happen in 27?

On 2014-09-12 17:57:29 -0400, Roger Light wrote:

I've had no response from the person who submitted a pull request to mosquitto.py that I then asked them to submit here instead.

It makes things a bit awkward because I can't use their code, but anything I write now would almost certainly come out very very similar now that I've already seen it.

I'd be very happy to receive a new, clean patch to achieve this functionality.

On 2015-01-12 19:31:52 -0500, Roger Light wrote:

This will be included in the 1.1 release.

On 2015-06-02 12:23:16 -0400, Muhammad Satrio wrote:

anyone have solved this issue?

On 2015-06-02 12:26:22 -0400, Juan Carlos Jimenez wrote:

Yes, Muhammad, wildcard certs are working fine in the latest version of paho.

On 2015-06-02 12:34:46 -0400, Muhammad Satrio wrote:

yes, you right. i just need to update paho with the latest version.
and it works
thanks jimenez

client does not detect connection failure

migrated from Bugzilla #475579
status UNCONFIRMED severity normal in component MQTT-Python for 1.2
Reported in version 1.1 on platform PC
Assigned to: Roger Light

On 2015-08-21 07:50:17 -0400, Gideon Farrell wrote:

If Client has connected, and then connection is lost (for my tests I kill the MQTT broker):

a) the Client does not seem to detect that the connection has been terminated (or at least I see no way to be notified of such)
b) nor does it report any sort of message send failure, so messages are permanently lost (I have confirmed that they are)

Cannot close client event thread cleanly

migrated from Bugzilla #467422
status UNCONFIRMED severity normal in component MQTT-Python for 1.2
Reported in version 1.1 on platform PC
Assigned to: Roger Light

Original attachment names and IDs:

On 2015-05-15 12:54:35 -0400, Cefn Hoile wrote:

Created attachment 253513
Example code

I'm running a simple unit test within the Twisted.trial framework, intending to use their Deferred object for handling the asynchronous nature of these tests.

The file attached shows the reference code. Unfortunately the invocation of loop_stop causes an Error...

Traceback (most recent call last):
File "runtests.py", line 64, in tearDown
self.receiver.loop_stop()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 1320, in loop_stop
self._thread.join()
File "/usr/lib/python2.7/threading.py", line 940, in join
raise RuntimeError("cannot join current thread")
exceptions.RuntimeError: cannot join current thread

runtests.MqttTestCase.test_messaged

Ran 1 tests in 2.882s

FAILED (errors=1)

On 2015-05-18 08:28:27 -0400, Cefn Hoile wrote:

Sorry not to be explicit about invocation. To invoke the test, I'm running...

trial runtests.py

...with the attached Example code file.

That maps to the Twisted trial utility which is contributed by the Ubuntu/Debian package python-twisted-core

$ apt-file search /usr/bin/trial
python-twisted-core: /usr/bin/trial

The test case gets all the way through to receiver_messaged, and it's only the tidyup which seems to be a problem.

Instead of disconnecting and stopping threads in tearDown, I can replace the method with

def tearDown(self):
pass

Then the test suite hangs waiting for CTRL+C

After hitting CTRL+C the Test is then reported as successful, but of course if I can't automate the termination of Paho threads using loop_stop then I can't build any kind of test suite.

On 2015-05-20 05:22:05 -0400, Cefn Hoile wrote:

I found the nature of the bug/feature and a workaround.

The issue is that the event which triggers termination of the 'receiver' thread (where receiver is a paho.mqtt.client.Client) is an event (on_message) arising from within the receiver's own loop.

This has got to be a really common scenario, honestly - that the receiver's lifecycle is terminated on a message receive for example.

As a result in my case receiver.loop_stop() is being called within the thread begun by receiver.loop_start(). Because there is a join() call in receiver.loop_stop to try and join with the original thread, the thread is therefore attempting to join with itself.

As a workaround I threw the call into another thread as below, but I don't really see why this would be necessary and I think the logic of loop_stop should handle this scenario.

Thread(target=self.receiver.loop_stop).start()

Recommend Client.loop_stop() has a change in its logic or a meaningful error indicating to the developer how to solve the problem. Being able to shut down a client on receipt of a message is a pretty fundamental feature which should not create surprising errors, and require extra Thread-spawning.

Paho does not support the SNI extension of TLS

migrated from Bugzilla #471037
status UNCONFIRMED severity enhancement in component MQTT-Python for 1.2
Reported in version 1.2 on platform All
Assigned to: Roger Light

On 2015-06-25 14:04:34 -0400, Juan Carlos Jimenez wrote:

The current implementation of Paho Python does not support the Server Name Indication extension of TLS.

This means that if a server has 2 VPS's trying to use TLS in the same port the connection will fail.

SNI support was added to the ssl module in the python version 2.7.9.

I have submitted a patch that will try to use SNI by default (pretty much every single SSL library out there supports it nowadays). If the ssl module does not support SNI, it will fall back to the non-SNI implementation.

You can find it here: https://git.eclipse.org/r/#/c/50658/

I'm currently using that patch and it is working fine for me.

Just opening the bug report for reference.

On 2015-06-25 17:50:34 -0400, Roger Light wrote:

Thanks for the report and the gerrit push, I had spotted it I've just been quite busy recently. I'll try to have a look soon.

Errno 10035 on Client() instantiation

migrated from Bugzilla #432949
status CLOSED severity normal in component MQTT-Python for ---
Reported in version unspecified on platform PC
Assigned to: Roger Light

On 2014-04-16 13:11:09 -0400, David Parker wrote:

C:\Console-2.00b148-Beta_32bit\Console2>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.

import paho.mqtt.client
cli = paho.mqtt.client.Client()
Traceback (most recent call last):
File "", line 1, in
File "C:\PYTHON27\lib\site-packages\paho\mqtt\client.py", line 400, in init
self._sockpairR, self._sockpairW = _socketpair_compat()
File "C:\PYTHON27\lib\site-packages\paho\mqtt\client.py", line 258, in _socketpair_compat
sock1.connect(("localhost", port))
File "C:\PYTHON27\lib\socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 10035] A non-blocking socket operation could not be completed immediately

To get this working on my system I simply hacked client.py as follows:
_socketpair_compat(
...
try:
sock1.connect(("localhost", port))
except socket.error as err:
(msg) = err
if msg.errno != errno.EINPROGRESS and err.errno != EAGAIN:
raise

I have no idea if it was the right thing to do nor what the wider implications of the change I made are, but file under "works for me, for now" :)

I only see this problem on my Windows 7 system, various flavours of linux are fine without this fix/hack.

On 2014-04-16 16:02:18 -0400, Roger Light wrote:

Thanks for the report, this is actually a duplicate bug although the description is quite similar.

*** This bug has been marked as a duplicate of bug 431698 ***

subscribe() checking for isinstance(topic, str) may be not be sufficient.

Suppose somebody sends a json encoded topic to be subscribed, in that case, if in python 2.7, the isinstance() function returns false, since the json encoded topic gets converted into unicode.

So checking for both str and unicode will be a better and safer way. Even when the topic is sent in the tuple or list format, in both the cases, the individual topic strings may be unicode.

Fail to connect using client.connect

migrated from Bugzilla #446062
status CLOSED severity normal in component MQTT-Python for 1.1
Reported in version v0.5 on platform PC
Assigned to: Roger Light

On 2014-10-06 10:59:00 -0400, Micha Shepher wrote:

Running on ubuntu 14.04 with the python bindings I notice the following:
After

client = mqtt.client()
print client.connect('localhost', 1883, 60)

This appears to work (MQTT_ERR_SUCCESS). However, syslog complains:

Oct 6 16:48:15 sr01000458 mosquitto[15820]: New connection from 192.168.17.80.
Oct 6 16:48:15 sr01000458 mosquitto[15820]: Invalid protocol "MQTT" in CONNECT from 192.168.17.80.
Oct 6 16:48:15 sr01000458 mosquitto[15820]: Socket read error on client (null), disconnecting.

The same code (taken from the examples) works fine connecting to iot.eclipse.org, mosquitto.org, m2m.eclipse.org and all other remote brokers.

Also, the local broker runs fine with the command line clients mosquitto_sub and mosquitto_pub.

On 2014-11-04 10:03:56 -0500, Roger Light wrote:

This is down to the Python client attempting to connect with the MQTT v3.1.1 protocol by default. If the broker rejects the connection, it should then attempt to connect with MQTT v3.1 instead. Some brokers (including old versions of mosquitto) don't reject the connection "properly" so it is not really possible to detect this scenario correctly.

The reason that iot.eclipse.org and test.mosquitto.org work is because they support MQTT v3.1.1. Presumably the versions of mosquitto_pub and _sub that you have match the version of mosquitto you have, so they don't try to use MQTT v3.1.1.

For you, the problem can be solved by upgrading your version of mosquitto. I'm not entirely sure what the best long term solution is though.

On 2015-01-12 19:43:12 -0500, Roger Light wrote:

I'm marking this bug as a duplicate of 451735 because the solution is the same, even though what you've reported is slightly different. This should hopefully make it easier to track.

*** This bug has been marked as a duplicate of bug 451735 ***

Calling message_callback_add within a callback causes deadlock

migrated from Bugzilla #459012
status UNCONFIRMED severity normal in component MQTT-Python for 1.1
Reported in version 1.1 on platform Other
Assigned to: Roger Light

On 2015-02-03 06:09:31 -0500, Ed Morris wrote:

The following code locks up when a message is published to the topic 'bar'.

!/usr/bin/python

import paho.mqtt.client as paho

def on_foo_message(mqttc,request,msg):
print("foo on_message")
pass

def on_message(mqttc,request,msg):
print("global on_message")
mqttc.subscribe("foo", 0)
print("Subscribed to foo")
mqttc.message_callback_add("foo/+",on_foo_message)
print("Added callback to foo")

mqttc = paho.Client()
broker = "127.0.0.1"
mqttport = 1883
mqttc.on_message = on_message
mqttc.connect(broker, mqttport, 60)
mqttc.subscribe("bar", 0)
mqttc.loop_forever()

I think it is because the call to self._callback_mutex.acquire() in message_callback_add never exits. This is because the mutex was already acquired in _handle_on_message and will not release until the on_message callback has finished - which cannot happen.

On 2015-06-10 22:38:22 -0400, YuLun Shih wrote:

Same issue here, I think it's all about _callback_mutex

keepalive value of 0 causes client to enter into indefinite loop

In one of the test cases, keepalive option was passed to 0
This caused MQTT client to enter into a never ending loop and it keept on creating connection with broker and destroying them. Client was stuck at following location:

client.py", line 1281, in loop_forever
    time.sleep(1)

The behavior was same with client.connect() functions as well as publish functions.

Ideally keepalive of 0 should either cause an invalid argument return or should internally revert to a default value.

paho.mqtt.publish multiple function will throw exception if target token list is empty

migrated from Bugzilla #461574
status UNCONFIRMED severity major in component MQTT-Python for 1.1
Reported in version 1.1 on platform PC
Assigned to: Roger Light

On 2015-03-06 06:08:59 -0500, henry john wrote:

def _do_publish(c):
"""Internal function"""
m = c._userdata[0]
c._userdata = c._userdata[1:] # throw exception is userdata contains only one element.
if type(m) is dict:
topic = m['topic']
try:
payload = m['payload']
except KeyError:
payload = None
try:
qos = m['qos']
except KeyError:
qos = 0
try:
retain = m['retain']
except KeyError:
retain = False
elif type(m) is tuple:
(topic, payload, qos, retain) = m
else:
raise ValueError('message must be a dict or a tuple')

c.publish(topic, payload, qos, retain)

bug fix version:
def _do_publish(c):
"""Internal function"""
if not c._userdata:
c.disconnect()
return
m = c._userdata.pop()
if type(m) is dict:
topic = m['topic']
try:
payload = m['payload']
except KeyError:
payload = None
try:
qos = m['qos']
except KeyError:
qos = 0
try:
retain = m['retain']
except KeyError:
retain = False
elif type(m) is tuple:
(topic, payload, qos, retain) = m
else:
raise ValueError('message must be a dict or a tuple')

c.publish(topic, payload, qos, retain)

advise: To get more readability, the code should better write with the pep8 style guide.

catch all except blocks KeyboardInterrupt

migrated from Bugzilla #477353
status UNCONFIRMED severity minor in component MQTT-Python for 1.2
Reported in version 1.1 on platform PC
Assigned to: Roger Light

Original attachment names and IDs:

On 2015-09-14 07:19:05 -0400, matt venn wrote:

Created attachment 256550
diff

something like this:

try:
client.loop_forever()
except KeyboardInterrupt as e:
print("ending")

doesn't work properly because there is a bare except clause in loop():

except:
return MQTT_ERR_UNKNOWN

the diff below fixes that by handling KeyboardError with a raise

if hosts file not set up correctly, Client constructor will fail

migrated from Bugzilla #439277
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version 1.0 on platform PC
Assigned to: Roger Light

On 2014-07-09 14:31:38 -0400, Justin Scherer wrote:

In the Client constructor, there is a call to the following function:
_socketpair_compat()

In the preceding function, there is a call to socket.bind that passes the following tuple in:
("localhost", 0)

Now, everyone should have a hosts file in their etc that gives the following to localhost:
localhost 127.0.0.1

But, there are embedded systems and forms of Linux that do not do this. I would suggest the following improvement to the codebase to make this a more hardy build:

check to see if localhost is defined in the hosts file, if errno -2 gets thrown, then just pass in "127.0.0.1". If anyone would like to check this, you can get rid of your hosts file in /etc and try to run the code from the file.

I can also make this correction if anyone feels that it needs to be done. I would be happy to.

On 2014-09-12 17:31:49 -0400, Roger Light wrote:

This is now fixed in the repository, thanks very much for the report.

Reconnect fails when inflight messages == max_inflight_messages

migrated from Bugzilla #443935
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version future on platform PC
Assigned to: Roger Light

On 2014-09-12 08:15:44 -0400, Hiram van Paassen wrote:

When there is a connection failure which last long enough to fill the out_messages list and sets self._inflight_messages == self._max_inflight_messages the MQTT library stops sending out messages when connected again.

Possible solution:
reset self._inflight_messages to 0 in "_messages_reconnect_reset_out()" in case self._inflight_messages => self._max_inflight_messages

Reproduction path:
Make a client which publishes every 5 seconds
Set max_inflight to 1 (default also works but takes longer)
Severe the connection to the broker (In our case pull the wan cable from the accesspoint the client is connected to)
Wait untill inflight_messages is higher than max_inflight
Restore connection

Observe the MQTT library accepts new publishes but does not actually send publish MQTT packets. Neither for new nor for old publishes

While the connection is severed the MQTT library only gives MQTT_ERR_NO_CONN as long as self._inflight_messages < self._max_inflight_messages

On 2014-09-12 08:20:01 -0400, Hiram van Paassen wrote:

Additional information:
This is using qos = 2

This happens because self._inflight_messages is only decreased after PUBREL or PUBACKCOMP and those are not send for PUBLISHes that are never received by the broker

On 2014-09-12 08:31:00 -0400, Hiram van Paassen wrote:

diff --git a/src/paho/mqtt/client.py b/src/paho/mqtt/client.py
index a28c81f..8a8c456 100755
--- a/src/paho/mqtt/client.py
+++ b/src/paho/mqtt/client.py
@@ -1822,6 +1822,7 @@ class Client(object):
pass
else:
m.state = mqtt_ms_invalid

  •            self._inflight_messages = 0
     self._out_message_mutex.release()
    

    def _messages_reconnect_reset_in(self):

On 2014-09-12 16:27:02 -0400, Roger Light wrote:

Thanks for this, I've pushed a change that I think fixes the bug.

On 2014-09-15 08:15:25 -0400, Hiram van Paassen wrote:

Seems that you missed a change:

You also need to add:

diff --git a/src/paho/mqtt/client.py b/src/paho/mqtt/client.py
index a817f78..b46dc1e 100755
--- a/src/paho/mqtt/client.py
+++ b/src/paho/mqtt/client.py
@@ -2138,9 +2138,9 @@ class Client(object):
if m.qos > 0 and m.state == mqtt_ms_queued:
self._inflight_messages = self._inflight_messages + 1
if m.qos == 1:

  •                    m.state = mqtt_ms_wait_puback
    
  •                    m.state = mqtt_ms_wait_for_puback
                 elif m.qos == 2:
    
  •                    m.state = mqtt_ms_wait_pubrec
    
  •                    m.state = mqtt_ms_wait_for_pubrec
                 rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup)
                 if rc != 0:
                     return rc
    

On 2014-09-15 10:42:10 -0400, Roger Light wrote:

Yep, you're right. Thanks. That's pushed as well now.

Failing to set MQTTv311/MQTTv31 protocol on Client object

migrated from Bugzilla #440169
status RESOLVED severity normal in component MQTT-Python for 1.1
Reported in version 1.0 on platform PC
Assigned to: Roger Light

On 2014-07-22 17:59:47 -0400, Andy Piper wrote:

client = mqtt.Client(client_id="", clean_session=True, userdata=None, protocol=MQTTv311)
client.connect("localhost", 1883, 60)

Results in:
File "subscribe.py", line 16, in
client = mqtt.Client(client_id="", clean_session=True, userdata=None, protocol=MQTTv31)
NameError: name 'MQTTv311' is not defined

The same applies with both MQTTv31 and MQTTv311.
Setting protocol to the numeric value of 4 does work.

On 2014-07-30 10:10:10 -0400, Roger Light wrote:

I replied to this by email, didn't realise it hadn't got through.

Andy, this looks like a namespace problem - neither MQTTv31 nor
MQTTv311 are global Python variables. Try mqtt.MQTTv31 or
mqtt.MQTTv311 instead. I guess this probably needs a documentation
addition somewhere.

On 2014-07-30 14:50:04 -0400, Andy Piper wrote:

Sounds like patching the doc / pydoc would resolve this, yes. Thanks!

On 2014-09-12 17:41:09 -0400, Roger Light wrote:

I've added some details to the in-code documentation, so this is now fixed.

High CPU load while emptying the message cache after a reconnect.

migrated from Bugzilla #452672
status RESOLVED severity enhancement in component MQTT-Python for 1.1
Reported in version 1.1 on platform All
Assigned to: Roger Light

On 2014-11-21 10:37:52 -0500, W Boerendans wrote:

Python Paho MQTT Client V1.1

Description

The calculation of max_packets in loop_write(), line: 1093 is incorrect and results in huge amount of useless iterations. This will happen when a connection with the broker is restored after a while, and messages are cached using existing buffers from the library.
The calculation of max_packets is based on the number of elements in self._out_messages and self._in_messages, which are not related with max_packets at this point.
Also list self._out_packet will only consist one message each time.

Reproduction path

When the connection between the MQTT broker and the python paho client is disconnected, messages that needs to be published by calling the publish() method, will be cached in self._out_messages.

Situation: The number of messages to be published is, for example, one per five seconds. After 10 minutes, the connection is restored. The list self._out_messages contains now 120 messages.

After the connection with the broker is set-up, cached messages from self._out_messages will be published again by the library retry mechanism.
The for loop in loop_write() will iterate from zero to the length of lists out_messages and in_messages. This is useless because self._out_packet will only contain one message at the time.
After the package is sent, the method _packet_write() will try to get a new packet from self._out_packet (line: 1552), but self._out_packet is empty.
Due to this issue, the for loop in loop_write() will iterate, in this case, 120x120 times for 120 messages.
For high performance systems, like PCs this is not really an issue, but for smaller ARM based single core systems it is and will lead to high cpu load.

Possible fixes/ideas

  • max_packets is always 1, remove the for loop.
  • To calculate max_packets, the length of self._out_packet should be used instead of self._out_messages and self._in_messages.
  • Refactor some code in loop_write, packet_write.

On 2015-02-01 11:04:17 -0500, Roger Light wrote:

This should be fixed in the 1.1 release.

topic_matches_sub() incorrectly filter some subscriptions

('sport/#', 'sport/') -> False instead of True

Also, some invalid filters are accepted.

('sport+', 'sport') -> True which is incorrect. etc

Here my proposal, which is simpler than the previous code, can detect invalid subscriptions, and runs faster (by about 30%) :

def topic_matches_sub(sub, topic):
    "return None if the subscription is invalid (maybe raise an exception ?)"

    if not sub or not topic:
        # invalid (all topic names and topic filters MUST be at least one character long)
        return None

    if topic[0] == '$' and sub[0] != '$':
        return False

    sub_l, topic_l = sub.split('/'), topic.split('/')
    sub_sz, topic_sz = len(sub_l), len(topic_l)

    for i, level in enumerate(sub_l):

        if level == '#':
            if i + 1 < sub_sz:
                return None # invalid ('#' not at end)
            return True

        elif level == '+':
            if i >= topic_sz:
                return False

        else:
            if '#' in level or '+' in level:
                return None # invalid ('#' / '+' in level part)
            if i >= topic_sz or level != topic_l[i]:
                return False

    return sub_sz == topic_sz

On the other hand, it doesn't detect all inconsistencies in topic format.

topic_matches_sub("test/6/#", "test/3")

migrated from Bugzilla #433687
status VERIFIED severity normal in component MQTT-Python for ---
Reported in version v0.5 on platform PC
Assigned to: Roger Light

On 2014-04-28 13:48:54 -0400, Tobias Assarsson wrote:

running:

!/usr/bin/python2

import paho.mqtt.client as client
client.topic_matches_sub("test/6/#", "test/3")
True

debugging the client.topic_matches_sub with prints after the
"if sub[spos] == topic[tpos]"
and one in the else-case where result turns False:

t == t
e == e
s == s
t == t
/ == /

last test is missing (6 != 3).

On 2014-04-28 16:23:59 -0400, Roger Light wrote:

Thanks very much for the report, well spotted!

I've pushed a commit which fixes the bug.

Python client timeout if behind a HTTP proxy

migrated from Bugzilla #457256
status CLOSED severity normal in component MQTT-Python for 1.1
Reported in version v0.5 on platform PC
Assigned to: Roger Light

On 2015-01-12 10:32:39 -0500, DD G wrote:

Unable to use the Python client on a machine that sits behind a corporate HTTP proxy. There doesn't seem to be a way to configure the proxy details.

I was able to make mosquitto_sub command line tool work using proxychains as a workaround. However a similar approach failed with the Python script.

!/usr/bin/env python

import paho.mqtt.client as mqtt
import time

client = mqtt.Client()
client.connect("test.mosquitto.org", 1883, 60)
temp = 1

client.loop_start()
while True:
temp = temp + 1
client.publish("house/temp/xxxx123", temp, retain=True)
time.sleep(10)

client.loop_forever()

when invoked without proxychains:

python test.py

python broker-sys.py
Traceback (most recent call last):
File "tests.py", line 31, in
client.connect("test.mosquitto.org", 1883, 60)
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 600, in connect
return self.reconnect()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 722, in reconnect
self._sock = socket.create_connection((self._host, self._port), source_address=(self._bind_address, 0))
File "/usr/lib/python2.7/socket.py", line 571, in create_connection
raise err
socket.error: [Errno 101] Network is unreachable

with proxychains (proxy IP changed to 99.99.99.99):

proxychains python test.py
ProxyChains-3.1 (http://proxychains.sf.net)
|S-chain|-<>-99.99.99.99:8080-<><>-127.0.0.1:54202-<--denied
Traceback (most recent call last):
File "test.py", line 26, in
client = mqtt.Client()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 410, in init
self._sockpairR, self._sockpairW = _socketpair_compat()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 262, in _socketpair_compat
sock1.connect(("localhost", port))
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 111] Connection refused

For reference mosquitto_pub with proxychains:

proxychains mosquitto_pub -d -h test.mosquitto.org -t "house/temp/xxxx123" -m 100
ProxyChains-3.1 (http://proxychains.sf.net)
|S-chain|-<>-99.99.99.99:8080-<><>-85.119.83.194:1883-<><>-OK
Received CONNACK
Sending PUBLISH (d0, q0, r0, m1, 'house/temp/xxxx123', ... (3 bytes))

On 2015-01-12 10:34:25 -0500, DD G wrote:

Using python 2.7 and paho-mqtt was installed using:

sudo pip install paho-mqtt

On 2015-01-12 19:51:03 -0500, Roger Light wrote:

Can proxychains be configured to not proxy the connections to 127.0.0.1?

On 2015-01-13 04:59:03 -0500, DD G wrote:

It appears that this might be possible by applying a patch to proxychains:

http://serverfault.com/questions/481408/proxychains-is-redirecting-packets-destined-to-local-machine-to-the-proxy-server

but it doesn't seem to work in the package that is in the Ubuntu 14.04 repo.

I put the appropriate line in the proxychains.conf:

localnet 127.0.0.0/255.0.0.0

and the python still has the same error

proxychains python test.py
ProxyChains-3.1 (http://proxychains.sf.net)
|S-chain|-<>-99.99.99.99:8080-<><>-127.0.0.1:35760-<--denied
Traceback (most recent call last):
File "test.py", line 26, in
client = mqtt.Client()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 410, in init
self._sockpairR, self._sockpairW = _socketpair_compat()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 262, in _socketpair_compat
sock1.connect(("localhost", port))
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 111] Connection refused

On 2015-01-16 04:34:12 -0500, Roger Light wrote:

I'm afraid the conclusion I've had to come to here is that the problem is that proxychains doesn't support disabling proxying of connections to localhost. You will have to find a proxy solution that allows you to decide which connections are proxied and which aren't. I'm surprised this isn't already a feature to be honest.

I'm closing this bug as "not eclipse" because I don't believe this is a bug in the Paho Python client.

On 2015-01-16 07:00:24 -0500, DD G wrote:

I agree with you that the proxychains aspect of this tkt is not a Paho Python client issue.

However I was only using that as a workaround for the underlying issue, namely that you cannot use the Paho Python client is you are behind a HTTP proxy.

So can we add that as a feature request please?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.