How to use Rust and MQTT in your Next Project

Photo by Andras Vas on Unsplash

Why do you want to buy an IoT device? In most of the cases, you want to obtain more control over your home. Maybe you just want to monitor things or even control them remotely. Of course, you can rely on the supplied apps of the manufacturers. But as a programmer, this is not your only option. Maybe, you want to get a message when the washing machine is done, or you would like to get a warning when the devices consume too much power. In these cases, you can take a look at MQTT. In this article, we’ll build a small MQTT client in Rust that listens to an MQTT broker and writes messages. So let’s get started.

What is MQTT

So first, what is MQTT? MQTT is a lightweight, publish-subscribe, machine to machine (M2M) network protocol. It is optimized for low bandwidth and high latency. But how does it work? MQTT works according to the publish-subscribe pattern. The senders of messages, which are named publishers, can not specify directly the receiver, which are called subscribers, but instead categorize published messages into classes called topics. This happens without the knowledge of how many subscribers subscribed to the topics. But how does this system work in reality? To make MQTT communication possible, we need a broker and a number of clients. The broker acts as an intermediary. The client can send a message to a topic on the broker. At the same time, the other clients can listen to the new message on the topic. After we have clarified these basics, we can head into the code.

For this small project, we use Rust. Rust is a good-performing and reliable language. The performance is comparable to C++ while having guarantees for memory-safety and thread-safety through its rich type system and ownership model. Both features are helpful in this particular case of a lightweight program running for a longer time in the background.

MQTT in Rust

For this article, we use the Rust crate (= library) rumqttc. This is a complete implementation of a MQTT client in Rust.

Firstly, we need to create a new Rust project.

cargo new mqtt-rust-demo

After switching into the new project we add rumqttc to our Cargo.toml.

rumqttc = "0.17.0"

After installing the library, we can start with the code.

The Client

The first thing we do is to create a variable with our connection data. This is done via MqttOptions.

let mut mqttoptions = MqttOptions::new("NAME", "YOUR BROKER", 1883);
mqttoptions.set_keep_alive(Duration::from_secs(5));

First, we need to specify the name of the client. It is important to give the client a unique name because two clients cannot have the same name on a broker. After that, the address and the port of the broker will follow as the next parameters. You can connect to a broker on the internet or your local network. Furthermore, you can set options. In our case, the client shall send a ’still active‘ message every five seconds.

let (mut client, mut connection) = Client::new(mqttoptions, 10);
client.subscribe("demo/mqtt", QoS::AtMostOnce).unwrap();

This is how we create a synchronous client. We fill it with our options. We get back a client object and an event loop. The latter will be important later. First, we say that we want to subscribe to the topic „demo/mqtt“.

QoS

Also, we specify the QoS level. Quality of Service (QoS) is a key feature of the MQTT Protocol. There are 3 different levels of QoS: At most once (0), At least once (1) Exactly once (2).

  • QoS 0 – At most once just sends the message (as in fire and forget) to the broker. This level should only be used in very reliable networks
  • QoS 1 – at least once sends the messages to the broker. At the same time, the sender stores the message locally until the broker sends an acknowledgment message (PUBACK message) back. The sender repeats the message when no acknowledgment message comes back after a while.
  • QoS 2 – exactly once sends the messages to the broker (which is not surprising). Like QoS 1, it waits until it gets an acknowledgment message (PUBREC) back. Until then, the sender emits the same published message with a duplicate flag. When the acknowledgment message is received by the sender, it responds with a PUBREL message to the broker. In the meantime, the sender stores the PUBREC message. When the broker receives the PUBREL message, it can safely discard all temporally stored data of this message. At the same time, the broker sends a PUBCOMP message to the sender. Now the sender can delete all temporal data.

The event loop


In this topic, we send in some messages. So we spawn a new task. In this task, we publish a message with a number in a topic.

thread::spawn(move || for i in 0..10 {
   client.publish("demo/mqtt", QoS::AtLeastOnce, false, vec![i; i as usize]).unwrap();
   thread::sleep(Duration::from_millis(100));
});

Next we come to our event loop object. We wrap it in an infinite loop, because it should always listen to the messages of the topic.
This is done with the command connection.iter().enumerate(). Next, we output the message.

for (_i, message) in connection.iter().enumerate() {
        println!("Message= {:?}", message);
}

Summary

This article marks only a very small introduction to the vast and interesting topic of MQTT. But let’s look at what you learned. You have a basic understanding of the structure of MQTT and created a small program in Rust which can send and receive messages. That is a great start!

Here is the code of this article:

https://gist.github.com/ngarske/cc5257fff416459f10fd88c422e173cb


Beitrag veröffentlicht

in

,

von

Schlagwörter:

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert