eclipse-paho/paho.mqtt.python

ReasonCode.names is missing a ReasonCode.packet_name

Opened this issue · 6 comments

While reading the docs about ReasonCode.names at https://eclipse.dev/paho/files/paho.mqtt.python/html/types.html#paho.mqtt.reasoncodes.ReasonCode
I was wondering why the packet_name useful to know where things come from is not listed. The only way I found was using https://github.com/eclipse/paho.mqtt.python/blob/master/src/paho/mqtt/reasoncodes.py#L190 (__repr__()) as getName() returns the name only.

Using that function gives me ReasonCode(Disconnect, 'Unspecified error') which is better than nothing.

I also would be happy if getName() would return an array where 0 is the name and 1 is the packet_name or another way I can get the packet_name.

The purpose of ReasonCode is to encapsulate a Reason Code; it needs to know the packet type because this is needed to translate some reason codes, for example 0 could mean Success, Normal disconnection or Granted QoS 0 depending upon the packet type.

I would assume that it does not expose information about the packet type is because it's intention was to communicate the Reason Code (and your use-case was not foreseen).

Can you please show how/where you would use the info?

Sure, for example: if you have a callback on_disconnect and want to print the reason for disconnecting to the log, you currently just get Unspecified error. One could write (without being code correct) MQTT dicsonnected: getName(), it would be important to know what was the origin (packet name) causig it like MQTT dicsonnected: getPacket() : getName(). This would help debugging a lot.
Just have a running client connected to mosquitto running as docker and reboot the broker docker. And this is an easy cause... There is a difference in printing Unspecified as error and Disconnect : Unspecified error. This is the repo I maintain running paho-mqtt.

The ReasonCode passed to on_disconnect would only ever be be created with a DISCONNECT packet type. However, this does not always mean that a DISCONNECT packet was actually received. So, in your example, the output would always be Disconnect : XXX (where XXX may change) and you may as well hard code the Disconnect bit.

This is why I requested an example; I don't think that making this data more accessible is really going to help you. If you are in the on_disconnect then you know the connection has been lost (and one potential cause is the receipt of a DISCONNECT packet). Most other callbacks are going to use a similar setup.

If you are in the on_disconnect then you know the connection has been lost.

As there are mostly more than one packet types possibe per ID (name), having additional info about the reason is helpful to narrow down issues. The easy example of rebooting a mosquitto container is just a placeholder for more complex problems. That the connection was lost is naturally given by the callback. I want to destinguish the reason as best as possible. It is not hurting anyone providing that info, but can help finding causes more easily. The info is already here an just needs to be made available.

You could do something like this:

import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes

# 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} and packet {PacketTypes.Names[reason_code.packetType]}")
    # 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)
mqttc.loop_forever()

Output:

Connected with result code Success and packet Connack

I doubt that a getter will be added to ReasonCode because it would have a limited audience and is likely to be confusing (the packetType in ReasonCode might not have actually ever been received).

I have tested this with on_disconnect and this works great and as expected. ✔️

The combination:

from paho.mqtt.packettypes import PacketTypes
...
on_connect | on_disconnect
print(f"Connected with result code {reason_code} and packet {PacketTypes.Names[reason_code.packetType]}")

should be part of the documentation.
Having that, one can decide if he is going to use this extended logging capability.
Many thanks pointing to it.