paho.mqtt.python icon indicating copy to clipboard operation
paho.mqtt.python copied to clipboard

How can we use MQTTv5 in client_sub-class.py or a class which inherits mqtt.Client

Open takerfume opened this issue 3 years ago • 3 comments

I modified client_sub-class.py to use MQTTv5 like below.

However I got an error.

Is there any way to use MQTTv5 for a class which inherits mqtt.Client class?

My code (MQTTv5 version of client_sub-class.py).

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

class MyMQTTClass(mqtt.Client):

    def on_connect(self, mqttc, obj, flags, rc, props):  # props is necessary for MQTTv5
        print("Connected: '"+str(flags)+"',"+ f"obj:{obj}"+" '"+str(rc)+"', '"+str(props))

    def on_connect_fail(self, mqttc, obj):
        print("Connect failed")

    def on_message(self, mqttc, obj, msg):
        # Get the response properties, abort if they're not given
        props = msg.properties
        if not hasattr(props, 'ResponseTopic') or not hasattr(props, 'CorrelationData'):
            print("No reply requested")
            return

        corr_id = props.CorrelationData
        reply_to = props.ResponseTopic

        # The command parameters are in the payload
        nums = json.loads(msg.payload)

        # The requested command is at the end of the topic
        res = 0


        # Now we have the result, res, so send it back on the 'reply_to'
        # topic using the same correlation ID as the request.
        print("Sending response "+str(res)+" on '"+reply_to+"': "+str(corr_id))
        props = mqtt.Properties(PacketTypes.PUBLISH)
        props.CorrelationData = corr_id

        payload = json.dumps(res)
        mqttc.publish(reply_to, payload, qos=1, properties=props)

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

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

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

    def run(self):
        self.connect("broker", 1883, 60)
        self.subscribe("/cmd/camera/shutter", qos=1) # このqosの値は0でいいのかも?

        rc = 0
        while rc == 0:
            rc = self.loop()
        return rc

if __name__ == "__main__":
    mqttc = MyMQTTClass(client_id="my_mqtt_class", protocol=mqtt.MQTTv5)
    rc = mqttc.run()

    print("rc: "+str(rc))

Error I got.

client_1  | Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b''
client_1  | Sending SUBSCRIBE (d0, m1) [(b'/cmd/camera/shutter', 1)]
client_1  | Received CONNACK (0, 0)
client_1  | Caught exception in on_connect: on_connect() missing 1 required positional argument: 'props'
client_1  | Traceback (most recent call last):
client_1  |   File "main.py", line 4, in <module>
client_1  |     rc = mqttc.run()
client_1  |   File "/clients/nodes/camera_node.py", line 70, in run
client_1  |     rc = self.loop()
client_1  |   File "/root/.local/share/virtualenvs/clients-ClhoSkV5/lib/python3.8/site-packages/paho/mqtt/client.py", line 1120, in loop
client_1  |     return self._loop(timeout)
client_1  |   File "/root/.local/share/virtualenvs/clients-ClhoSkV5/lib/python3.8/site-packages/paho/mqtt/client.py", line 1164, in _loop
client_1  |     rc = self.loop_read()
client_1  |   File "/root/.local/share/virtualenvs/clients-ClhoSkV5/lib/python3.8/site-packages/paho/mqtt/client.py", line 1556, in loop_read
client_1  |     rc = self._packet_read()
client_1  |   File "/root/.local/share/virtualenvs/clients-ClhoSkV5/lib/python3.8/site-packages/paho/mqtt/client.py", line 2439, in _packet_read
client_1  |     rc = self._packet_handle()
client_1  |   File "/root/.local/share/virtualenvs/clients-ClhoSkV5/lib/python3.8/site-packages/paho/mqtt/client.py", line 3039, in _packet_handle
client_1  |     return self._handle_connack()
client_1  |   File "/root/.local/share/virtualenvs/clients-ClhoSkV5/lib/python3.8/site-packages/paho/mqtt/client.py", line 3138, in _handle_connack
client_1  |     on_connect(
client_1  | TypeError: on_connect() missing 1 required positional argument: 'props'

takerfume avatar Feb 11 '22 13:02 takerfume

Have you tried initializing the mqtt.Client class and passing the MQTTv5 as the init argument? Adding the following line of code to the init_ function might be able to specify it. mqtt.Client.init(self, protocol=M!TTv5)

Sohaib90 avatar Jun 24 '22 13:06 Sohaib90

Hi no it doesn't work with above code, it shows this error: "AttributeError: type object 'Client' has no attribute 'init'"

more over it has a typing error I corrected it: mqtt.Client.init(self, protocol=MQTTv5)

Solution is in TTN forum please refer: https://www.thethingsnetwork.org/forum/t/problem-retrieving-data-using-tts-mqtt-tab-py/53924/2

amin-tayebi avatar Sep 07 '22 07:09 amin-tayebi

Of course it does not work because it is mqtt.Client.__init__()

How I have done in my application is something like this

class MyClient (mqtt.Client): 
    def __init__(self):
       mqtt.Client.__init__(self, protocol=MQTTv5) 

Sohaib90 avatar Sep 07 '22 13:09 Sohaib90

Based on the above I believe this is probably resolved. However to test I ran the below which appeared to work fine. If you are still having issues please feel free to reopen with more details.

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

class MyMQTTClass(mqtt.Client):

    def on_connect(self, mqttc, obj, flags, rc, props):  # props is necessary for MQTTv5
        print("Connected: '"+str(flags)+"',"+ f"obj:{obj}"+" '"+str(rc)+"', '"+str(props))

    def on_connect_fail(self, mqttc, obj):
        print("Connect failed")

    def on_message(self, mqttc, obj, msg):
        # Get the response properties, abort if they're not given
        props = msg.properties
        if not hasattr(props, 'ResponseTopic') or not hasattr(props, 'CorrelationData'):
            print("No reply requested")
            return

        corr_id = props.CorrelationData
        reply_to = props.ResponseTopic

        # The command parameters are in the payload
        nums = json.loads(msg.payload)

        # The requested command is at the end of the topic
        res = 0


        # Now we have the result, res, so send it back on the 'reply_to'
        # topic using the same correlation ID as the request.
        print("Sending response "+str(res)+" on '"+reply_to+"': "+str(corr_id))
        props = mqtt.Properties(PacketTypes.PUBLISH)
        props.CorrelationData = corr_id

        payload = json.dumps(res)
        mqttc.publish(reply_to, payload, qos=1, properties=props)

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

    def on_subscribe(self, mqttc, userdata, mid, reasonCodes, properties):
        print("Subscribed: "+str(mid)+" "+str(reasonCodes))

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

    def run(self):
        self.connect("mosquitto", 1883, 60)
        self.subscribe("/cmd/camera/shutter", qos=1) # このqosの値は0でいいのかも?

        rc = 0
        while rc == 0:
            rc = self.loop()
        return rc

if __name__ == "__main__":
    mqttc = MyMQTTClass(client_id="my_mqtt_class", protocol=mqtt.MQTTv5)
    rc = mqttc.run()

    print("rc: "+str(rc))

Note: This is part of an exercise to clean up old issues so that the project can move forwards. Due to the number of issues being worked through mistakes will be made; please feel free to reopen this issue (or comment) if you believe it's been closed in error.

MattBrittan avatar Jan 08 '24 04:01 MattBrittan