Simple CoAP Client Example | Qt CoAP 6.4.1

- Qt 6.4
- Qt CoAP
- Qt CoAP Examples
- Simple CoAP Client Example
- Qt 6.4.1 Reference Documentation

# Simple CoAP Client Example

     // Copyright (C) 2019 The Qt Company Ltd.
     // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

     #include "mainwindow.h"
     #include "optiondialog.h"
     #include "ui_mainwindow.h"

     #include <QCoapResourceDiscoveryReply>
     #include <QCoapReply>
     #include <QDateTime>
     #include <QFileDialog>
     #include <QHostInfo>
     #include <QMessageBox>
     #include <QMetaEnum>
     #include <QNetworkInterface>

     MainWindow::MainWindow(QWidget *parent) :
         QMainWindow(parent),
         ui(new Ui::MainWindow)
     {
         m_client = new QCoapClient(QtCoap::SecurityMode::NoSecurity, this);
         connect(m_client, &QCoapClient::finished, this, &MainWindow::onFinished);
         connect(m_client, &QCoapClient::error, this, &MainWindow::onError);

         ui->setupUi(this);

         ui->methodComboBox->addItem("Get", QVariant::fromValue(QtCoap::Method::Get));
         ui->methodComboBox->addItem("Put", QVariant::fromValue(QtCoap::Method::Put));
         ui->methodComboBox->addItem("Post", QVariant::fromValue(QtCoap::Method::Post));
         ui->methodComboBox->addItem("Delete", QVariant::fromValue(QtCoap::Method::Delete));

         fillHostSelector();
         ui->hostComboBox->setFocus();
     }

     MainWindow::~MainWindow()
     {
         delete ui;
     }

     void MainWindow::fillHostSelector()
     {
         const auto networkInterfaces = QNetworkInterface::allInterfaces();
         for (const auto &interface : networkInterfaces)
             for (const auto &address : interface.addressEntries())
                 ui->hostComboBox->addItem(address.ip().toString());
     }

     void MainWindow::addMessage(const QString &message, bool isError)
     {
         const QString content = "--------------- "
                 + QDateTime::currentDateTime().toString()
                 + " ---------------\n"
                 + message + "\n\n";
         ui->textEdit->setTextColor(isError ? Qt::red : Qt::black);
         ui->textEdit->insertPlainText(content);
         ui->textEdit->ensureCursorVisible();
     }

     void MainWindow::onFinished(QCoapReply *reply)
     {
         if (reply->errorReceived() == QtCoap::Error::Ok)
             addMessage(reply->message().payload());
     }

     static QString errorMessage(QtCoap::Error errorCode)
     {
         const auto error = QMetaEnum::fromType<QtCoap::Error>().valueToKey(static_cast<int>(errorCode));
         return QString("Request failed with error: %1\n").arg(error);
     }

     void MainWindow::onError(QCoapReply *reply, QtCoap::Error error)
     {
         const auto errorCode = reply ? reply->errorReceived() : error;
         addMessage(errorMessage(errorCode), true);
     }

     void MainWindow::onDiscovered(QCoapResourceDiscoveryReply *reply, QList<QCoapResource> resources)
     {
         if (reply->errorReceived() != QtCoap::Error::Ok)
             return;

         QString message;
         for (const auto &resource : resources) {
             ui->resourceComboBox->addItem(resource.path());
             message += "Discovered resource: \"" + resource.title() + "\" on path "
                     + resource.path() + "\n";
         }
         addMessage(message);
     }

     void MainWindow::onNotified(QCoapReply *reply, const QCoapMessage &message)
     {
         if (reply->errorReceived() == QtCoap::Error::Ok)
             addMessage("Received observe notification with payload: " + message.payload());
     }

     static QString tryToResolveHostName(const QString hostName)
     {
         const auto hostInfo = QHostInfo::fromName(hostName);
         if (!hostInfo.addresses().empty())
             return hostInfo.addresses().first().toString();

         return hostName;
     }

     void MainWindow::on_runButton_clicked()
     {
         const auto msgType = ui->msgTypeCheckBox->isChecked() ? QCoapMessage::Type::Confirmable
                                                               : QCoapMessage::Type::NonConfirmable;
         QUrl url;
         url.setHost(tryToResolveHostName(ui->hostComboBox->currentText()));
         url.setPort(ui->portSpinBox->value());
         url.setPath(ui->resourceComboBox->currentText());

         QCoapRequest request(url, msgType);
         for (const auto &option : m_options)
             request.addOption(option);
         m_options.clear();

         const auto method = ui->methodComboBox->currentData(Qt::UserRole).value<QtCoap::Method>();
         switch (method) {
         case QtCoap::Method::Get:
             m_client->get(request);
             break;
         case QtCoap::Method::Put:
             m_client->put(request, m_currentData);
             break;
         case QtCoap::Method::Post:
             m_client->post(request, m_currentData);
             break;
         case QtCoap::Method::Delete:
             m_client->deleteResource(request);
             break;
         default:
             break;
         }
         m_currentData.clear();
     }

     void MainWindow::on_discoverButton_clicked()
     {
         QUrl url;
         url.setHost(tryToResolveHostName(ui->hostComboBox->currentText()));
         url.setPort(ui->portSpinBox->value());

         QCoapResourceDiscoveryReply *discoverReply = m_client->discover(url, ui->discoveryPathEdit->text());
         if (discoverReply)
             connect(discoverReply, &QCoapResourceDiscoveryReply::discovered, this, &MainWindow::onDiscovered);
         else
             QMessageBox::critical(this, "Error", "Something went wrong, discovery request failed.");
     }

     void MainWindow::on_observeButton_clicked()
     {
         QUrl url;
         url.setHost(tryToResolveHostName(ui->hostComboBox->currentText()));
         url.setPort(ui->portSpinBox->value());
         url.setPath(ui->resourceComboBox->currentText());

         QCoapReply *observeReply = m_client->observe(url);
         if (!observeReply) {
             QMessageBox::critical(this, "Error", "Something went wrong, observe request failed.");
             return;
         }

         connect(observeReply, &QCoapReply::notified, this, &MainWindow::onNotified);

         ui->cancelObserveButton->setEnabled(true);
         connect(ui->cancelObserveButton, &QPushButton::clicked, this, [=]() {
             m_client->cancelObserve(url);
             ui->cancelObserveButton->setEnabled(false);
         });
     }

     void MainWindow::on_addOptionsButton_clicked()
     {
         OptionDialog dialog;
         if (dialog.exec() == QDialog::Accepted)
             m_options = dialog.options();
     }

     void MainWindow::on_contentButton_clicked()
     {
         QFileDialog dialog(this);
         dialog.setFileMode(QFileDialog::AnyFile);
         if (!dialog.exec())
             return;

         const auto fileName = dialog.selectedFiles().back();
         QFile file(fileName);
         if (!file.open(QIODevice::ReadOnly)) {
             QMessageBox::critical(this, "Error", QString("Failed to read from file %1").arg(fileName));
             return;
         }

         m_currentData = file.readAll();
     }

     void MainWindow::on_resourceComboBox_editTextChanged(const QString &text)
     {
         ui->observeButton->setEnabled(!text.isEmpty());
     }

     void MainWindow::on_methodComboBox_currentIndexChanged(int index)
     {
         Q_UNUSED(index);

         const auto method = ui->methodComboBox->currentData(Qt::UserRole).value<QtCoap::Method>();
         ui->contentButton->setEnabled(method == QtCoap::Method::Put || method == QtCoap::Method::Post);
     }