MQTT Client Using Paho Cpp
With the IoT revolution, software has become a key component. Developing software products that are: lightweight, efficient, and scalable requires the proper tools such as MQTT and C++.
This post describes how to install libraries, configure the CMake and build a simple C++ client that can post a literal text message to a cloud MQTT broker.
Why?
So what is MQTT, and why choose C++?
MQTT [1] is a publishing/subscribe messaging protocol that is lightweight and efficient, scalable, reliable, secure, and well-supported [2], and ideal for connecting remote devices with a small code footprint and minimal network bandwidth.
C++ is a general-purpose programming, which is the third most popular language[3] among the most energy-efficient programs [4] with a large set of libraries from the standard library and Boost and wide hardware support for high performance such as the Cuda library or the Intel Library
For further information regarding MQTT check the MQTT essentials
Tutorial
For this tutorial, we use C++ 17, CMake, and the Paho MQTT CPP Client. https://ports.macports.org/port/paho.mqtt.cpp/. Is assumed some C++ and CMake experience. The complete code can be found at https://gitlab.com/hurtadosanti/MqttClient.
Install the Libraries
This requires three steps on an ubuntu 22.04 machine: 1) Install the build libraries, 2) Install Paho for C and 3) Install Paho for C++.
NOTE: In a Mac, MacPorts provides the Paho MQTT CPP packet
-
Install the compilation essentials
sudo apt install build-essential cmake git pkg-config gcc g++ libssl-dev
-
Clone build and install the Eclipse Paho C Client Library for the MQTT Protocol.
git clone https://github.com/eclipse/paho.mqtt.c.git cd paho.mqtt.c cmake -Bbuild -H. -DPAHO_ENABLE_TESTING=OFF -DPAHO_BUILD_STATIC=ON -DPAHO_WITH_SSL=ON -DPAHO_HIGH_PERFORMANCE=ON sudo cmake --build build/ --target install sudo ldconfig
-
Clone, build and install the Eclipse Paho MQTT C++ Client Library.
cd ~/software git clone https://github.com/eclipse/paho.mqtt.cpp cd paho.mqtt.cpp cmake -Bbuild -H. -DPAHO_BUILD_STATIC=ON -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=FALSE sudo cmake --build build/ --target install sudo ldconfig
Configure CMake
The required Libraries are Threads and the PahoMqtt.
set(CMAKE_CXX_STANDARD 17)
find_package(Threads REQUIRED)
find_package(PahoMqttCpp REQUIRED)
Create a HiveMQ Cloud account
Create and get the credentials from https://console.hivemq.cloud
Write the Client
To write the client we use the Paho Async Client.
First, we write the callback to handle the messages
class LiteralCallback : public virtual mqtt::callback,
public virtual mqtt::iaction_listener {
private:
mqtt::async_client &client;
const std::string topic;
public:
LiteralCallback(mqtt::async_client &client, std::string &topic) : client(client), topic(topic) {
}
void connected(const mqtt::string &string) override {
callback::connected(string);
mqtt::subscribe_options options;
mqtt::properties properties;
client.subscribe(topic, 0, options, properties);
std::cout << "Subscribed to topic"<<topic<< std::endl;
};
void message_arrived(mqtt::const_message_ptr message) override {
callback::message_arrived(message);
std::cout << "message arrived on topic: " << message->get_topic() << ", and message: " << message->get_payload()
<< std::endl;
};
void on_failure(const mqtt::token &asyncActionToken) override {
std::cout << "on failure" << std::endl;
if (asyncActionToken.get_message_id() != 0)
std::cout << " for token: [" << asyncActionToken.get_message_id() << "]" << std::endl;
std::cout << std::endl;
}
void on_success(const mqtt::token &asyncActionToken) override {
std::cout << "on success" << std::endl;
}
~LiteralCallback() override = default;
};
Afterward, write the client and pass the cloud credentials through program arguments.
int main(int argc, char *argv[]) {
const std::string clientId("cloud_client_2");
std::string topicName("test");
const int qos = 1;
std::string username;
std::string password;
std::string serverAddress;
if (argc > 3) {
username = argv[1];
password = argv[2];
serverAddress = argv[3];
} else {
std::cerr << "Broker Settings should be set" << std::endl;
return 1;
}
try {
mqtt::async_client cli(serverAddress, clientId);
mqtt::connect_options connectOptions(username, password);
mqtt::ssl_options sslOptions;
connectOptions.set_ssl(sslOptions);
LiteralCallback cb(cli, topicName);
cli.set_callback(cb);
auto connection = cli.connect(connectOptions, nullptr, cb);
connection->wait();
mqtt::topic topic(cli, topicName, qos);
auto publishToken = topic.publish("Cloud Client Testing");
std::cout<<"Message send"<<std::endl;
publishToken->wait();
std::cout<<"Message received"<<std::endl;
cli.disconnect()->wait();
}
catch (const mqtt::exception &exc) {
std::cerr << exc << std::endl;
return 2;
}
return 0;
}
Compile and Build
To compile, create a build folder for the binaries and run the cmake task.
mkdir build && cd build
cmake ../
When successful build the binary using make.
make
Run a test
Finally, execute the binary mqtt_client
passing the three program arguments in the correct order.
mqtt_client <username> <password> ssl://<url>
Now you should see the following:
on success
on success
Subscribed to topictest
Message send
message arrived on topic: test, and message: Cloud Client Testing
Message received
References