Using The Python MQTT-SN Client

The MQTT-SN client used here is the client from the RSMB source files but upgraded to python 3, and modified to work in a similar fashion to the Paho MQTT client.

I created it so that I could learn more about MQTT-SN and you should note it is still a work in progress.

I would not recommend it in a production environment and would be grateful if you would let me know of any problems with it.

Downloads are at the end.

The client consists of 4 files.

MQTT-SN-python-client-files

You can copy these source files into the site packages folder under a suitable folder (e.g mqtt-sn) or alternatively set the path in your scripts to access the client.

Example:

sys.path.append('c:/python34/steve/mqttsclient/')

Client Files Overview

The MQTTSN.py handles the packet packing and unpacking, and you don’t need to edit this.

It has a very important function right at the end called unpackPacket() shown below:

def unpackPacket((buffer, address)):
  if MessageType(buffer) != None:
    packet = objects[MessageType(buffer)]()
    packet.unpack(buffer)
  else:
    packet = None
  return packet, address

This function extracts the message Type from the received packet and calls the appropriate function to decode the packet.

Note: objects is a list of message type names and is just above the function.

objects

The function is called from the MSQTTInternal.py script.

The MSQTTInternal.py script handles the incoming packet in the receive function.

receive-function

The receive function is called as part of a loop or can be called manually.

Normally it is started from the call function (at bottom of script ) which itself is started from the MQTTClient.py script when you do a client.start() or client.loop_start()

mqtt-sn-call-function

This is the loop() as per the MQTT client

This file also has two important functions at the top. They are lookfor() and waitfor.

These functions basically look for a message type and wait for a message type they are generally used as follows:

look for CONNACK
wait for CONNACK

Note: You need to do a lookfor before a waitfor or the waitfor will always fail.

The observe if statement which is part of the receive decides if the message type just received matches what we are looking for.

observe-function

Underneath you will see a collection of if, and if else statements which look for packet type and then call the appropriate callback function if available

mqtt-sn-test-packet-trigger-callback

MQTTSNclient.py File

The main file is the MQTTSNclient.py file.

The file has two classes the callback and the Client classes.

You will need to include it at the top of you scripts using:

import MQTTSNclient.callback as callback
import MQTTSNclient.Client as Client

Note : MQTTSNclient is the file that contains the scripts.

Example Usage Publish and Subscribe Script

The following script subscribes to a topic and publishes messages on the same topic and displays the published and received messages.

We start with the imports.

mqtt-sn-script-0

Notice the sys.path call which you will need to set depending on where you place the MQTT-SN client files.

Now we create the connection:mqtt-sn-script-1

Notice the use of lookfor() followed by waitfor().

You should also notice flags like client.connected_flag=False.

This follows the same style as used in the MQTT client and so you could use the following to replace the lookfor and waitfor sections.

mqtt-sn-script-2

I’ve shown the alternative code using the flags that are set in the callback functions as per the mqtt client.

 

The Client Class

This works like the standard Paho MQTT client.

The following methods are available along with the parameters:

connect(host=”localhost”,port=1883,duration=60,cleansession=True,will=False)

Connects to a broker. Clean session has the same meaning as MQTTv3 and means that the state is stored on the broker and the client can reconnect start with the same state.

The will is a flag and when true tells the broker to request a will topic an message from the client.

disconnect()

Dis-connects from a broker. No parameters

TopicId, rc=subscribe(topic, qos=0)

Subscribe to a topic by long name,short name or topicId. This is a blocking function as it waits for a suback message and returns the topic Id and a return code (0=Success)

This makes the on_subscribe callback redundant. I implemented it this way as it makes no sense proceeding until you have the topic ID and the topic ID is returned by the suback so we wait for it.

The register function,unsubscribe function and register function work the same way.

msgId=unsubscribe(topic)

UnSubscribe from a topic by long name,short name or topicId. This is a blocking function as it waits for the unsuback message.

It returns a message Id

TopicId, rc=(register topicName)

Register a topic by long name. This is a blocking function as it waits for a regack message and returns the topic Id and a return code (0=Success)

publish(topic, payload, qos=0, retained=False)

Publish a message using a topic ID or short name. QOS (0,1,2). Retained flag will tell the broker to keep this message until overwritten.

publish(host,port,topic,payload,retained=False,host=”localhost”,port=10000)

Publish with qos 3 or -1. This doesn’t require a connection and is ideal for sensors. The QOS is fixed at 3 or -1.You need to pass in the host and port.

lookfor(msgType)

Look for a message type. The message types (taken from the specification) are shown below:

mqtt-sn-message-types

The lookfor is used in conjuction with the waitfor to wait for an acknowledgement message.

waitfor( msgType, msgId=None)
Blocking functions waits for the message type and must be proceeded by a lookfor.
When using lookfor/waitfor callbacks are not used.

set_gateway(gwid,active=False)

Set a gateway to active or inactive. gqid is a number and the id of the gateway.

add_gateway(gwid,host,port,duration)

Adds gateway to a list of gateways. Called when the client receives an advertise packet or a response to a search gateway request.

Search_GWs(multicast_address,multicast_port)

search for a gateway. Parameters are the multicast address and port.

The response is a GWINFO packet

start()

registerCallback(callback)

Used to register callback class. Must be used when using callbacks

loop(interval=.001)

This is used to run the loop manually.

loop_start_gw()

Start the gateway (muticast)loop. If you are using any of gateway discover methods then this must be called.Starts a new thread.

loop_stop_gw()

Stops the multicast loop and must be called at the end if loop_start_gw() has been called.

loop_start()

Start a loop and must be called to process incoming messages UDP messages.Starts a new thread.

loop_stop()

Stops the loop and must be called at the end if loop_start() has been called.

set_will(will_msg,will_topic,will_qos=0,will_retained=False)

Set will message and topic. Parameters are

will_msg=The message to be sent
will_topic= The will topic
qos=qos of the message
will_retained= retained flag of the message

update_will_topic(will_topic,will_qos=0,will_retained=False)

Update will topic. Parameters are

will_topic= The will topic
qos=qos of the message
will_retained= retained flag of the message

update_will_msg(will_msg)

Update will message . Parameters are

will_msg=The message to be sent

Callbacks

The callback functions are defined in the MQTTSNclient script but can be overridden in the script by sub classing the callback class.

To use the predefined Callbacks use:

from MQTTSNclient import Callback #callback functions
##other code
client.registerCallback(Callback())

To override the on_connect and on_disconnect calbacks use:

from MQTTSNclient import Callback #callback functions
##other code
##
class MyCallback(Callback):
  def on_connect(self,client,address,rc):
    print("in on connect my callback")
    if rc==0:
      client.connected_flag=True
    else:
      client.bad_connect_flag=True
  def on_disconnect(self,client,cause):
    if debug:
      print("default connection Lost", cause)
    self.events.append("disconnected")
    client.connected_flag=False
##
client.registerCallback(MyCallback())

The callbacks defined in the Callback Class with the parameters are listed below.

on_connect(client,address,rc)

Triggered by an incoming CONNACK message. parameters are the client ,address of the broker, and the return code (see table below).

mqtt-sn-return-codes

on_disconnect(client,duration=None)

Triggered by the DISCONNECT message. parameters are the client, and there is an option duration which is used by sleeping clients.

on_subscribe(client,TopicId,MsgId,rc)

Not Used

on_message(client,TopicId,Topicname, payload, qos, retained, msgid)

Triggered by an incoming PUBLISH. Parameters are

client= the client
TopicId=the topic ID (int) or 0 if a short topic
Topicname=Short topic name if short topic (topic type-2)
payload=The incoming message in bytes.
qos-QOS of message
retained=retained flag of message.

on_regack(client, TopicId)

Not Used

on_register(client, TopicId, TopicName)

Triggered by an incoming register message from the gateway/broker

on_puback(client,msgId,rc,qos)

Triggered by a PUBACK which is received when a message with qos=1 is published. The returned parameters are

client= the client
msgId= Message id of the message can be compared with the message id of the published message
rc=return code

The following is taken from the specification and should be read as the PUBACK is different for MQTTv3 in that it can be sent for all messages regarding of qos as it can contain a reason code.

publish-mqtt-sn
on_willtopicresp(client,rc)

Triggered when the gateway broker acknowledges receipt of the will topic message.

rc=0 is ok

on_willmsgresp(client,rc)

Triggered when the gateway broker acknowledges receipt of the willmessage message.

rc=0 is ok

Video – RSMB and Python MQTT-SN Client Demo

Client Download

Examples Download

The following example scripts are included:

  1. The pub_sub-sn.py script from above.
  2. A standalone publish script publish-sn.py that uses the topic registration to publish.
  3. A publish script that publishes without a connection. (quick_publish_sn.py)
  4. A standalone subscribe script that subscribes to a topic and displays received messages in a continuous loop
  5. A Gateway discovery script which finds a gateway and publishes to it (gateway.py)
  6. A multicast scan test script. Change the port and multicast group to see messages on that group/port (multicast-scan.py)

Related Tutorials

Please rate? And use Comments to let me know more

36 comments

  1. Hi, Steve!

    Congratulations for the codes for mqtt-sn communications. I used the pub and sub codes with an mqtt-sn broker and it worked very well.

    The only drawback I had was that when using a topic string in the publishing code the message does not reach the broker but does not throw any execution errors. When I use a topic id the message arrives without problem

    I have used other codes in C language using topic string and the message reaches the broker without any problem.

    I also wanted to ask you, is it possible to use ssl communication for mqtt-sn in your code?

    ¡Regards!

          1. I see the destination/source ports, see same data, not sure what? Is this mean, that it is mqtt-sn ?

  2. Hey Steve,

    is there a way to read binary data? I need to read protobuffer data and 0xFF and other bytes are not received.

  3. Hello Steve,
    I am running the script pub-sub-sn.py from your demo scripts.
    I get an error
    sys.version_info(major=3, minor=7, micro=3, releaselevel=’final’, serial=0)
    threads 1
    connecting 192.168.2.110
    clean sessions= True
    threads 2
    topic for topic1 is bulbs1
    connected now subscribing
    Traceback (most recent call last):
    File “pub-sub-sn.py”, line 88, in
    rc, topic1_id = client.subscribe(topic1,1)
    TypeError: cannot unpack non-iterable NoneType object

    Can you please tell what changes should i do?
    I am using Raspberry Pi and my RSMB broker is on port 1885.

    1. Hi
      If you have just recently downloaded the client then it may not work with the older scripts unless you modify them.
      I will try to update those scripts in the next few days so that they work ok.
      If you read the tutorial here it may help you troubleshoot the problem.
      http://www.steves-internet-guide.com/python-mqttsn-client/
      I will post a comment here when I have updated them.
      Sorry about that
      RGds
      Steve

      1. Demos scripts are now updated and work with the new client. The gateway scripts can be downloaded from the gateway tutorial

        1. Hello Steve,
          Thanks for the reply.
          New updated sccripts are working. One question, when i run the pub-sub-mqtt-mqttsn.py and pub-sub-mqttsn-mqtt.py scripts, I can only see the publishing message and not the received message? why ?

          also, Where can I find the gateway tutorial?

          Regards
          Abhishek

          1. Hi
            I will check the scripts again but it is probably that you are using the wrong port for MQTT. on my setup I use 1883 for MQTT and 10000 for MQTT-SN. Check the MQTT port and you may need to edit the config file
            Rgds
            Steve

          2. No reply option on the latest comment, so replying here.

            I checked the port. MQTT is on 1883 and MQTT-SN is on 1885 . RSMB broker is also on and working. Still the same error?

            You mentioned about gateway tutorial. Where can I find it ?

            Thanks !

          3. Hi,

            I checked the port. MQTT is on 1883 and MQTT-SN is on 1885. RSMB broker is also on and working. Still it shows only publishing messages and not received messages.
            what changes should i do ?

            Thanks !

          4. pub-sub-mqttsn-mqtt-1.py and pub-sub-mqtt-mqttsn-1.py work ok on my side they need to be run together and test publishing from mqtt to mqtt-sn and vice versa.
            Put bit more delay in the publish loop so you can see what is happening and check the on message callbacks have print statements in them and they are commented out.
            Rgds
            Steve

          5. Hello Steve,
            I tried what you suggested, executed both the scripts together. Commented the print statement in the on_connect loop. Still I have the same error , cant see receiving message ?
            One more question to clear, Is the RSMB broker here acting as the MQTT-SN gateway?

          6. Not sure why use the ask steve page and send me some screen shots and I’ll take a look.
            RSMB is an mqtt broker and a MQTT-SN broker.
            Because it links two different protocols you could say it is acting as a gateway.
            rgds
            Steve

  4. Hello
    I have a question, when I use the pub_sub_sn and the rsmb broker, it is no necessary to register the topics, why? even if these aren´t short names, can you explain me this? Thank you

    1. To publish to a topic you need to use a short name,topic id or pre registered topic. Do have have an example of what is working that you think is incorrect?
      rgds
      Steve

      1. Thanks for you reply
        First, I start the RSMB Broker, then I run my script where the client subscribe succesfully to the topics, and after that it start publishing, receiving the client the message of the topics to which it is subscribed. However, I read that it´s necessary to register our topics sending the register message to the broker from the client in order to be able to subscribe to the them, so why I can subscribe without have to send the register messages? (My topics are normal, as example: light or humidity).

      2. On second thought, the question could be? It is necessary to register before subscribe?, register and subscribe return a topicid, so which could be the correct use of the register message? and, Is necessary be subscribed to be able to publish?
        Thanks for your help, I am new to MQTT SN

        1. If you need to receive messages or pub/rec then just subscribe as that gets the topicid
          If you only need to publish then register to get the topic id.

  5. Hi, I want to ask you about the callbacks, I have tried to load them in my script in order to activate when a message like disconnect or connect, but it never happens, so I tried commenting the lookfor from the method disconnect on MQTTSNclient and works but it takes some seconds before to do what the callback says. So, I am using in a wrong way the callbacks?
    Thanks

    1. Hi
      The lookfor is from the old pythonv2.7 code. I modified the code to work like the mqtt client which uses the callbacks.
      The callbacks should work. Send me the code you are using with the callbacks and I will look at it. Use the ask steve page to do that and I can reply with email.

  6. Hi
    How I want to send PINGREQ and PINGRESP messages from client, how I could call them, i see that these methods aren´t defined in the mqttsnclient library, how I could call them?

  7. Hi, I have a question, when I use these scripts in two differents PCs, I want to capture the MQTTSN traffic with wireshark (it has a mqttsn filter), but it doesnt capture anything, what should I do to make Wireshark capture this traffic?

  8. These scripts work over wi-fi, right?

    How would you suggest using these scripts to use MQTT-SN over bluetooth?

  9. Do you plan on putting your client code that has been updated to Python 3 code up on github? Perhaps fork the version there that you updated?

Leave a Reply

Your email address will not be published. Required fields are marked *