MQTT – Subscribing to Topics

In the last article I described how you can easily publish data via MQTT in C/C++ with the help of the library paho. Receiving data is just as easy. MQTT provides that you can subscribe to topics for this. Data published under these topics is then sent.

Waiting for callback

As in the last article, I will again use the library paho. The core of the subscription is a callback method that informs the application about the arrival of new data.

int MQTTClient_messageArrived(void *context, char *topicName, int topicLen, MQTTClient_message *message)

The parameters are largely self-explanatory. context refers to a user-defined date that is passed at the time of registration of the callback method. contex can also simply be NULL if it is not needed.

The callback method is registered with

int MQTTClient_setCallbacks (MQTTClient  handle, void *context, MQTTClient_connectionLost *cl, MQTTClient_messageArrived *ma, MQTTClient_deliveryComplete *dc)

With this method, callbacks can be set up for various purposes. In the specific case, I only want to receive published messages. With this, the call looks like this:

int MQTTClient_setCallbacks(client, NULL, NULL, messageArrived, NULL);

I implemented the callback method in such a way that it simply outputs the topic and the message. In a productive case, the data would perhaps be stored in a database or prepared in a GUI.

int MQTTClient_messageArrived(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    printf("Topic: %s \t Message: %.*s\n", topicName, message->payloadlen, (char*) message->payload);
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

The return value 1 or true signals to paho that the message could be processed properly. Otherwise, paho tries to deliver the message again.I didn’t do any further experiments with this. However, I would use this function with great caution. I could not find a way to define something like max retries or see if a fixed number is set. There is a danger of getting the application into a kind of infinite loop and possibly provoking buffer overflows.

It is important to know that topicName and message are not automatically released again after the callback method returns. For this, MQTTClient_freeMessage and MQTTClient_free must be called. In the case of topicName, the memory can also be released with the usual C methods, which, according to the documentation, leads to problems under Windows when using different compilers. It is therefore recommended to always use MQTTClient_free.

Download the project here.

The IP address in the demo project must be adapted to the respective case. Make sure that the MQTT server is online. Then the programme can be started.

For testing, a message is generated with the command line tool mosquitto_pub:

mosquitto_pub -t test -m hello

Now you should see the following output in the terminal:

Terminal session that displays the output of revpimqttsub when the above message is sent.
Output of revpimqttsub

Synchronous or asynchronous, that is the question

As an alternative to the callback method described above, the following method can also be used to poll for new messages:

int MQTTClient_receive ( MQTTClient handle,char **topicName, int *topicLen, MQTTClient_message **message,unsigned long timeout )

As you can see from the two ways of receiving messages, paho can be operated synchronously and asynchronously. Depending on the method used, a few things have to be taken into account, which I have disregarded for my simple demos.

If callback methods are registered with MQTTClient_setCallbacks(), paho runs asynchronously. This means that paho also takes care of ensuring the quality of service. So this should be the preferred way. If the API is to be accessed by several threads, however, the MQTTAsync API must be used, as the normal API is not thread safe.

If no callback methods are stored, paho runs synchronously and the application must ensure via regular polling that the keep-alive mechanism is running and Quality of Service is ensured. This can be done by regularly calling MQTTClient_receive(). If the application only sends data but does not subscribe to topics, MQTTClient_yield() can be used instead. If QoS1 or QoS2 is to be used, MQTTClient_waitForCompletion() must also be called after sending a message.

 

Leave a Reply

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