/*! * * Copyright (c) 2026 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file MqttClient.h * \author (original) Stephen Quong * \date (original) 30-Jul-2026 * */ #pragma once #include #include #include #include #include class QMqttClient; /*! * \brief Publishes messages to the cloud over MQTT. * \details Wraps QtMqtt's QMqttClient for a QoS 1 publishing session. * * The lifecycle is init() -> open() -> close(). init() only validates * the configuration and builds the TLS configuration from it; the * QMqttClient itself is created by open() and destroyed by close(), * or by an unsolicited disconnect. A close()/open() pair is therefore * a full reset, which is what allows the session to be reopened with * rotated credentials. * \note Connecting is asynchronous: open() only starts the attempt, and a * true return does not mean the broker accepted the session. * \note Must live on the thread that calls open(): the client's socket * belongs to the thread that constructs it. * \note The connection is always TLS. init() fails unless keyPath names a * readable private key. */ class MqttClient : public QObject { Q_OBJECT public: /*! * \brief Parameters for one MQTT session. */ struct Config { QString endpoint; // Broker FQDN or address; no scheme or trailing slash. quint16 port = 8883; // Broker port; the session is always TLS. QString certPath; // Client certificate for mTLS, PEM; optional. QString keyPath; // Unencrypted private key matching certPath, PEM; required. QString caPath; // CA bundle to verify the broker, PEM; optional, falls back // to the system CA set. QString clientId; // Must equal the IoT Thing name; the device policy scopes iot:Connect to it. quint16 keepAliveSecs = 30; // MQTT keep-alive interval; PINGREQ is QMqttClient's job. bool cleanSession = true; // No broker-side queue; durability is the device's job. }; explicit MqttClient(QObject *parent = nullptr); ~MqttClient() override; bool init(const Config &config); public Q_SLOTS: bool open(); void close(); bool publish(const QString &topic, const QByteArray &payload, qint64 messageId = -1); private: void onStateChanged(); void onMessageSent(qint32 id); void failPending(); QMqttClient *_client = nullptr; Config _config; QSslConfiguration _sslConfig; QHash _pending; };