summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaurice Kalinowski <maurice.kalinowski@qt.io>2018-12-14 13:19:06 +0100
committerMaurice Kalinowski <maurice.kalinowski@qt.io>2018-12-20 08:51:17 +0000
commitf5d0032d763435c6ab2a9d4015882878acff1589 (patch)
tree5bf104157883697737c59444b40427a4cad7dd83
parent306058b96ab8219a5176118e7cbe25d12b2e6aa6 (diff)
Add console examples
Other solutions provide minimal console applications for publishing and subscribing, which can then be used as tools. Task-number: QTBUG-69995 Task-number: QTBUG-71957 Change-Id: Ica4a856e25b540d089e1aa20f853b780c18d59dd Reviewed-by: hjk <hjk@qt.io>
-rw-r--r--examples/mqtt/consolepubsub/configuration.h307
-rw-r--r--examples/mqtt/consolepubsub/consolepubsub.pro6
-rw-r--r--examples/mqtt/consolepubsub/main_pub.cpp112
-rw-r--r--examples/mqtt/consolepubsub/main_sub.cpp112
-rw-r--r--examples/mqtt/consolepubsub/qtmqtt_pub.pro25
-rw-r--r--examples/mqtt/consolepubsub/qtmqtt_sub.pro25
-rw-r--r--examples/mqtt/mqtt.pro1
7 files changed, 588 insertions, 0 deletions
diff --git a/examples/mqtt/consolepubsub/configuration.h b/examples/mqtt/consolepubsub/configuration.h
new file mode 100644
index 0000000..b25920f
--- /dev/null
+++ b/examples/mqtt/consolepubsub/configuration.h
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QByteArray>
+#include <QCommandLineParser>
+#include <QCommandLineOption>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QLoggingCategory>
+#include <QString>
+#include <QMqttClient>
+#include <QSslSocket>
+
+struct Configuration
+{
+ QString topic;
+ QByteArray content;
+ quint8 qos;
+ bool retain{false};
+ bool useEncryption{false};
+};
+
+QMqttClient *createClientWithConfiguration(QCoreApplication *app,
+ Configuration *msg,
+ bool publish)
+{
+ QCommandLineParser parser;
+ if (publish)
+ parser.setApplicationDescription("Qt MQTT publish tool");
+ else
+ parser.setApplicationDescription("Qt MQTT subscription tool");
+
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ QCommandLineOption optionDebug("d",
+ QLatin1String("Enable debug messages / logging categories"));
+ parser.addOption(optionDebug);
+
+ QCommandLineOption optionFile("f",
+ QLatin1String("Specify the content of a file as message."),
+ QLatin1String("filename"));
+ if (publish)
+ parser.addOption(optionFile);
+
+ QCommandLineOption optionClientId("i",
+ QLatin1String("Specify a client ID. Defaults to random value."),
+ QLatin1String("clientid"));
+ parser.addOption(optionClientId);
+
+ QCommandLineOption optionKeepAlive("k",
+ QLatin1String("Specify the keep-alive value in seconds."),
+ QLatin1String("keepAlive"));
+ parser.addOption(optionKeepAlive);
+
+ QCommandLineOption optionMessageContent("m",
+ QLatin1String("Specify the message content. Defaults to"
+ " a null message."),
+ QLatin1String("messageContent"));
+ if (publish)
+ parser.addOption(optionMessageContent);
+
+ QCommandLineOption optionPassword("P",
+ QLatin1String("Provide a password."),
+ QLatin1String("password"));
+ parser.addOption(optionPassword);
+
+ QCommandLineOption optionPort("p",
+ QLatin1String("Network port to connect to. Defaults to 1883."),
+ QLatin1String("hostPort"),
+ QLatin1String("1883"));
+ parser.addOption(optionPort);
+
+ QCommandLineOption optionQos("q",
+ QLatin1String("Quality of service level to use for all messages."
+ "Defaults to 0."),
+ QLatin1String("qos"),
+ QLatin1String("0"));
+ parser.addOption(optionQos);
+
+ QCommandLineOption optionRetain("r",
+ QLatin1String("Specify the retain flag for a message."));
+ if (publish)
+ parser.addOption(optionRetain);
+
+ QCommandLineOption optionHost("s",
+ QLatin1String("MQTT server to connect to. Defaults to localhost."),
+ QLatin1String("hostName"),
+ QLatin1String("localhost"));
+ parser.addOption(optionHost);
+
+ QCommandLineOption optionMessageTopic("t",
+ QLatin1String("Specify the message topic."),
+ QLatin1String("messageTopic"));
+ parser.addOption(optionMessageTopic);
+
+ QCommandLineOption optionUser("u",
+ QLatin1String("Provide a username."),
+ QLatin1String("username"));
+ parser.addOption(optionUser);
+
+ QCommandLineOption optionVersion("V",
+ QLatin1String("Specify the protocol version. Options are "
+ "mqtt31, mqtt311, mqtt5. Defaults to mqtt311."),
+ QLatin1String("protocolVersion"),
+ QLatin1String("mqtt311"));
+ parser.addOption(optionVersion);
+
+ QCommandLineOption optionCaFile("cafile",
+ QLatin1String("Specify a file containing trusted CA "
+ "certificates to enable encrypted communication."),
+ QLatin1String("cafile"));
+ parser.addOption(optionCaFile);
+
+ QCommandLineOption optionCaPath("capath",
+ QLatin1String("Specify a directory containing trusted CA "
+ "certificates to enable encrypted communication."),
+ QLatin1String("capath"));
+ parser.addOption(optionCaPath);
+
+ parser.process(*app);
+
+ auto *client = new QMqttClient(app);
+
+ client->setHostname(parser.value(optionHost));
+ bool ok = true;
+ quint16 port = static_cast<quint16>(parser.value(optionPort).toInt(&ok));
+ if (!ok) {
+ qWarning() << "Invalid port specified:" << parser.value(optionPort);
+ return nullptr;
+ }
+ client->setPort(port);
+
+ if (parser.isSet(optionUser))
+ client->setUsername(parser.value(optionUser));
+ if (parser.isSet(optionPassword))
+ client->setPassword(parser.value(optionPassword));
+ if (parser.isSet(optionClientId))
+ client->setClientId(parser.value(optionClientId));
+ if (parser.isSet(optionVersion)) {
+ const QString version = parser.value(optionVersion);
+ if (version == QLatin1String("mqtt31"))
+ client->setProtocolVersion(QMqttClient::MQTT_3_1);
+ else if (version == QLatin1String("mqtt311"))
+ client->setProtocolVersion(QMqttClient::MQTT_3_1_1);
+ else if (version == QLatin1String("mqtt5"))
+ client->setProtocolVersion(QMqttClient::MQTT_5_0);
+ else {
+ qWarning() << "Invalid protocol version specified:" << version;
+ return nullptr;
+ }
+ }
+
+ if (parser.isSet(optionCaFile) || parser.isSet(optionCaPath)) {
+#ifdef QT_NO_SSL
+ qWarning() << "Qt has not been compiled with SSL support.";
+ return nullptr;
+#else
+ QList<QString> fileNames;
+ if (parser.isSet(optionCaFile))
+ fileNames.append(parser.value(optionCaFile));
+
+ if (parser.isSet(optionCaPath)) {
+ QFileInfo path(parser.value(optionCaPath));
+ if (!path.isDir()) {
+ qWarning() << "Specified capath is not a directory";
+ return nullptr;
+ }
+ auto entries = QDir(parser.value(optionCaPath)).entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
+ for (auto entry : entries)
+ fileNames.append(entry.absoluteFilePath());
+ }
+ if (fileNames.isEmpty()) {
+ qWarning() << "No certificate file found.";
+ return nullptr;
+ }
+
+ QList<QSslCertificate> defaultCerts;
+ for (auto it : fileNames) {
+ auto certificates = QSslCertificate::fromPath(it);
+ if (certificates.isEmpty() && parser.isSet(optionDebug))
+ qWarning() << "File " << it << " does not contain any certificates";
+ defaultCerts.append(certificates);
+ }
+ if (defaultCerts.isEmpty()) {
+ qWarning() << "No certificate could be loaded.";
+ return nullptr;
+ }
+
+ QSslSocket::addDefaultCaCertificates(defaultCerts);
+ msg->useEncryption = true;
+#endif
+ }
+
+ if (parser.isSet(optionDebug))
+ QLoggingCategory::setFilterRules(QLatin1String("qt.mqtt.*=true"));
+
+ msg->qos = static_cast<quint8>(parser.value(optionQos).toInt(&ok));
+ if (!ok || msg->qos > 2) {
+ qWarning() << "Invalid quality of service for message specified:" << msg->qos;
+ return nullptr;
+ }
+
+ if (parser.isSet(optionKeepAlive)) {
+ const quint16 keep = static_cast<quint16>(parser.value(optionKeepAlive).toUInt(&ok));
+ if (!ok) {
+ qWarning() << "Invalid keep alive value specified";
+ return nullptr;
+ }
+ client->setKeepAlive(keep);
+ }
+
+ if (publish) {
+ if (parser.isSet(optionFile) && parser.isSet(optionMessageContent)) {
+ qWarning() << "You cannot specify a file and a text as message.";
+ return nullptr;
+ }
+ if (parser.isSet(optionFile)) {
+ QFile file(parser.value(optionFile));
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "Could not open specified file for reading.";
+ return nullptr;
+ }
+ msg->content = file.readAll();
+ file.close();
+ }
+ if (parser.isSet(optionMessageContent))
+ msg->content = parser.value(optionMessageContent).toUtf8();
+ }
+
+ if (!parser.isSet(optionMessageTopic)) {
+ qWarning() << "You must specify a topic to publish a message.";
+ return nullptr;
+ }
+ msg->topic = parser.value(optionMessageTopic);
+
+ if (publish && !QMqttTopicName(msg->topic).isValid()) {
+ qWarning() << "The specified message topic is invalid.";
+ return nullptr;
+ }
+
+ if (!publish && !QMqttTopicFilter(msg->topic).isValid()) {
+ qWarning() << "The specified subscription topic is invalid.";
+ return nullptr;
+ }
+
+ if (publish && parser.isSet(optionRetain))
+ msg->retain = true;
+
+ // Output:
+ qInfo() << "Client configuration:";
+ qInfo() << " Host:" << client->hostname() << " Port:" << client->port()
+ << " Protocol:" << client->protocolVersion();
+ qInfo() << " Username:" << client->username() << " Password:" << !client->password().isEmpty();
+ qInfo() << " Client ID:" << client->clientId() << "Keep Alive:" << client->keepAlive();
+
+ return client;
+}
+
diff --git a/examples/mqtt/consolepubsub/consolepubsub.pro b/examples/mqtt/consolepubsub/consolepubsub.pro
new file mode 100644
index 0000000..6aee476
--- /dev/null
+++ b/examples/mqtt/consolepubsub/consolepubsub.pro
@@ -0,0 +1,6 @@
+TEMPLATE = subdirs
+
+SUBDIRS = \
+ qtmqtt_pub.pro \
+ qtmqtt_sub.pro
+
diff --git a/examples/mqtt/consolepubsub/main_pub.cpp b/examples/mqtt/consolepubsub/main_pub.cpp
new file mode 100644
index 0000000..b47fb8e
--- /dev/null
+++ b/examples/mqtt/consolepubsub/main_pub.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "configuration.h"
+
+#include <QCoreApplication>
+#include <QMqttClient>
+#include <QSslSocket>
+#include <QTimer>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+ QCoreApplication::setApplicationName(QStringLiteral("qtmqtt_pub"));
+ QCoreApplication::setApplicationVersion(QStringLiteral("1.0"));
+
+ // Create the client
+ Configuration description;
+ auto *client = createClientWithConfiguration(&a, &description, true);
+
+ if (!client)
+ return -1;
+
+ a.connect(client, &QMqttClient::errorChanged, [&client](const QMqttClient::ClientError e) {
+ if (e == QMqttClient::NoError)
+ return;
+
+ qWarning() << "Error Occurred:" << e << " Client state:" << client->state();
+ client->disconnectFromHost();
+ });
+
+ a.connect(client, &QMqttClient::messageSent, [&client] (quint32 id) {
+ qInfo() << "Message with ID:" << id << " sent";
+ client->disconnectFromHost();
+ });
+
+ a.connect(client, &QMqttClient::stateChanged, [&client] (QMqttClient::ClientState s) {
+ if (s == QMqttClient::Disconnected) {
+ client->deleteLater();
+ qApp->quit();
+ }
+ });
+
+ a.connect(client, &QMqttClient::connected, [&client, description]() {
+ qInfo() << "Message:";
+ qInfo() << " Topic:" << description.topic << " QoS:" << description.qos
+ << " Retain:" << description.retain;
+ qInfo() << " Content: " << description.content.left(50);
+ client->publish(description.topic,
+ description.content,
+ description.qos,
+ description.retain);
+ if (description.qos == 0)// 0 has no acknowledgment
+ QTimer::singleShot(500, client, &QMqttClient::disconnectFromHost);
+ });
+
+#ifndef QT_NO_SSL
+ if (description.useEncryption)
+ client->connectToHostEncrypted();
+ else
+#endif
+ client->connectToHost();
+
+ return a.exec();
+}
diff --git a/examples/mqtt/consolepubsub/main_sub.cpp b/examples/mqtt/consolepubsub/main_sub.cpp
new file mode 100644
index 0000000..9e94037
--- /dev/null
+++ b/examples/mqtt/consolepubsub/main_sub.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "configuration.h"
+
+#include <QCoreApplication>
+#include <QMqttClient>
+#include <QSslSocket>
+#include <QTimer>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+ QCoreApplication::setApplicationName(QStringLiteral("qtmqtt_sub"));
+ QCoreApplication::setApplicationVersion(QStringLiteral("1.0"));
+
+ // Create the client
+ Configuration description;
+ auto *client = createClientWithConfiguration(&a, &description, false);
+
+ if (!client)
+ return -1;
+
+ a.connect(client, &QMqttClient::errorChanged, [&client](const QMqttClient::ClientError e) {
+ if (e == QMqttClient::NoError)
+ return;
+
+ qWarning() << "Error Occurred:" << e << " Client state:" << client->state();
+ client->disconnectFromHost();
+ });
+
+ a.connect(client, &QMqttClient::stateChanged, [&client] (QMqttClient::ClientState s) {
+ if (s == QMqttClient::Disconnected) {
+ client->deleteLater();
+ qApp->quit();
+ }
+ });
+
+ a.connect(client, &QMqttClient::connected, [&client, description]() {
+ auto sub = client->subscribe(description.topic, description.qos);
+ client->connect(sub, &QMqttSubscription::stateChanged, [&client](QMqttSubscription::SubscriptionState s) {
+ qInfo() << "Subscription state:" << s;
+ if (s == QMqttSubscription::Unsubscribed)
+ client->disconnectFromHost();
+ });
+
+ client->connect(sub, &QMqttSubscription::messageReceived, [](const QMqttMessage &msg) {
+ qInfo() << "ID:" << msg.id()
+ << "Topic:" << msg.topic().name()
+ << "QoS:" << msg.qos()
+ << "Retain:" << msg.retain()
+ << "Duplicate:" << msg.duplicate()
+ << "Payload:" << msg.payload().left(50) << (msg.payload().size() > 50 ? "..." : "");
+ });
+ });
+
+#ifndef QT_NO_SSL
+ if (description.useEncryption)
+ client->connectToHostEncrypted();
+ else
+#endif
+ client->connectToHost();
+
+ return a.exec();
+}
diff --git a/examples/mqtt/consolepubsub/qtmqtt_pub.pro b/examples/mqtt/consolepubsub/qtmqtt_pub.pro
new file mode 100644
index 0000000..bfa84b7
--- /dev/null
+++ b/examples/mqtt/consolepubsub/qtmqtt_pub.pro
@@ -0,0 +1,25 @@
+QT -= gui
+QT += mqtt
+
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main_pub.cpp
+
+HEADERS += \
+ configuration.h
+
+target.path = $$[QT_INSTALL_EXAMPLES]/mqtt/consolepubsub
+INSTALLS += target
diff --git a/examples/mqtt/consolepubsub/qtmqtt_sub.pro b/examples/mqtt/consolepubsub/qtmqtt_sub.pro
new file mode 100644
index 0000000..c022650
--- /dev/null
+++ b/examples/mqtt/consolepubsub/qtmqtt_sub.pro
@@ -0,0 +1,25 @@
+QT -= gui
+QT += mqtt
+
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main_sub.cpp
+
+HEADERS += \
+ configuration.h
+
+target.path = $$[QT_INSTALL_EXAMPLES]/mqtt/consolepubsub
+INSTALLS += target
diff --git a/examples/mqtt/mqtt.pro b/examples/mqtt/mqtt.pro
index c734248..db620d0 100644
--- a/examples/mqtt/mqtt.pro
+++ b/examples/mqtt/mqtt.pro
@@ -1,5 +1,6 @@
TEMPLATE = subdirs
SUBDIRS += \
+ consolepubsub \
simpleclient \
subscriptions