mqtt_client

IMqttClient is a MQTT 5 client interface.
Note: Only MQTT version 5 is officially supported. WebSocket transport is not supported. For more information, refer to MQTT v5.0 spec .

File information

File common/interface/mqtt_client.h

Public functions Create
MQTTConnect
MQTTSubscribe
MQTTPublish
MQTTUnsubscribe
MQTTPing
MQTTDisconnect
MQTTSendAuthData
GetAliasByTopicName
GetNameByTopicAlias

Classes IMqttClient
UMqttClient

Data types MqttError
MQTTReasonCode
MQTTAuthReasonCode
MQTTClientDisconnectReason

Structs MqttUserProperty
MqttConnectCredentials
MqttWillOptions
MqttConnectOptions
MqttSubscribeOptions
MqttPublishOptions
MqttDisconnectOptions
MqttAuthOptions
MqttConnectAckInfo
MqttPublishRecvInfo
MqttPublishCompleteInfo

Examples Code Example

Classes

IMqttClient

class IMqttClient {
public:
    static IMqttClient* Create(class IIoMux* const iomux,
        class ISocketProvider* const tcpSocketProvider,
        class ISocketProvider* const tlsSocketProvider,
        class UMqttClient* const user,
        class IInstanceLog* const log,
        class IDns* const dns);

    virtual MqttError MQTTConnect(const char* broker,
                                  char* outputClientId,
                                  size_t outputClientIdSize,
                                  const char* inputClientId = nullptr,
                                  const MqttConnectOptions& options = {}) = 0;

    virtual MqttError MQTTSubscribe(dword subscriptionIdentifier,
                                    const char* topicFilter,
                                    const MqttSubscribeOptions& options = {}) = 0;

    virtual MqttError MQTTPublish(const char* topicName,
                                  const MqttPublishOptions& options = {}) = 0;

    virtual MqttError MQTTUnsubscribe(const char* topicFilter,
                                      const MqttUserProperty& userProperty = {}) = 0;

    virtual MqttError MQTTPing() = 0;

    virtual MqttError MQTTDisconnect(const MqttDisconnectOptions& options = {}) = 0;

    virtual MqttError MQTTSendAuthData(const char* authenticationMethod,
                                       const byte* authenticationData,
                                       word authenticationDataSize,
                                       const MqttAuthOptions& options = {}) = 0;

    virtual word GetAliasByTopicName(const char* topicName) const = 0;
    virtual const char* GetNameByTopicAlias(word alias) const = 0;
};

This class is the main interface for MQTT client functionality. It allows connecting to a broker via either TCP or TLS socket, publishing and subscribing to one or multiple topics (separated by commas), sending pings, handling authentication, and more. The ClientId can either be generated if nothing is passed, or an explicit ClientId can be used if provided. If you want to generate an ID, be sure to pass a buffer of at least 24 bytes because the generated ID is 23 bytes plus the null terminator.

Optional parameters are grouped into structs (e.g., MqttConnectOptions, MqttPublishOptions). All struct fields have sensible defaults, so only the fields that are actually needed have to be set.

Subscription Identifiers: When subscribing, a subscription identifier can be provided (e.g., 12). The user of this interface should store these identifiers to handle incoming messages properly.

QoS: Allowed values are 0, 1, or 2. If another value is used, the function returns IncorrectValue.

User Properties: Can be provided with comma-separated names and comma-separated values via MqttUserProperty. They correspond index-wise, e.g. userProp1,userProp2 for names and val1,val2 for values. Each name must have a matching value. A mismatch in the count (e.g., two names, one value) leads to an error.

Topic Aliases: You can use topicAlias inside MqttPublishOptions to assign or reuse aliases. If a topic alias already exists, you can publish with the same alias to avoid resending the full topic name. (Details are described in the MQTT v5 specification.)

Public functions

Create (static function)
Creates an IMqttClient instance.

Parameters

IIoMux * const iomux The iomux instance needed for socket communication.
ISocketProvider * const tcpSocketProvider A socket provider to create a TCP socket for MQTT transport.
ISocketProvider * const tlsSocketProvider A socket provider to create a TLS socket for secured MQTT (MQTT over TLS).
UMqttClient * const user An UMqttClient instance to receive callbacks from IMqttClient.
IInstanceLog * const log The log instance for logging.
IDns * const dns An optional DNS instance for DNS resolution.

Return Value

The IMqttClient* instance. Must be deleted if no longer used.
MQTTConnect
Connects to an MQTT broker. Optional parameters are grouped in MqttConnectOptions, which itself embeds MqttConnectCredentials and MqttWillOptions. If the broker is secured (TLS), set options.tls = true and use the corresponding port (e.g., 8883) via options.port.

Parameters

const char * broker The broker address or hostname.
char * outputClientId A buffer to store the generated or used client ID. If generating an ID, pass at least 24 bytes. Pass nullptr if an inputClientId is provided.
size_t outputClientIdSize Size of the outputClientId buffer. Pass 0 if an inputClientId is provided.
const char * inputClientId (Default: nullptr) If specified, this client ID is used for the MQTT connection. If nullptr, a client ID is generated and written to outputClientId.
const MqttConnectOptions & options (Default: {}) Optional connection parameters. See MqttConnectOptions.

Return Value

An MqttError indicating success or a specific error reason.
MQTTSubscribe
Subscribes to one or multiple topic filters separated by commas. For example: "test/light1, test/light2". QoS and other per-topic flags are specified in MqttSubscribeOptions as comma-separated strings matching the topic order, e.g. options.qosLevels = "0,2".

Parameters

dword subscriptionIdentifier Subscription identifier. The user should store this to correlate incoming messages.
const char * topicFilter The topic filter(s) to subscribe to, separated by commas if more than one.
const MqttSubscribeOptions & options (Default: {}) Optional per-topic flags. See MqttSubscribeOptions.

Return Value

An MqttError indicating success or a specific error reason.
MQTTPublish
Publishes a message to a topic. Payload, QoS, retain flag, and all optional properties are provided via MqttPublishOptions.

Parameters

const char * topicName The topic to publish to.
const MqttPublishOptions & options (Default: {}) Payload, QoS, retain, topic alias, and optional properties. See MqttPublishOptions.

Return Value

An MqttError indicating success or a specific error reason.
MQTTUnsubscribe
Unsubscribes from one or multiple topic filters (comma-separated).

Parameters

const char* topicFilter The topic filter(s) to unsubscribe from, separated by commas if more than one.
const MqttUserProperty & userProperty (Default: {}) Optional user property to attach to the UNSUBSCRIBE packet. See MqttUserProperty.

Return Value

An MqttError indicating success or a specific error reason.
MQTTPing
Sends a PINGREQ to the broker to keep the connection alive or check if the server is responsive. Typically used if no other MQTT traffic is ongoing for a longer period than the keep-alive interval.

Return Value

An MqttError indicating success or a specific error reason.
MQTTDisconnect
Disconnects from the broker. All optional parameters (reason string, session expiry, user property, server reference) are provided via MqttDisconnectOptions.

Parameters

const MqttDisconnectOptions & options (Default: {}) Disconnect reason and optional properties. See MqttDisconnectOptions.

Return Value

An MqttError indicating success or a specific error reason.
MQTTSendAuthData
Sends authentication data to the broker if needed (enhanced authentication). The reason code, optional reason string, and user property are provided via MqttAuthOptions.

Parameters

const char* authenticationMethod The authentication method (must match the one set during MQTTConnect if used).
const byte* authenticationData The binary authentication data to send.
word authenticationDataSize The size of the authentication data buffer.
const MqttAuthOptions & options (Default: {}) Reason code, optional reason string, and user property. See MqttAuthOptions.

Return Value

An MqttError indicating success or a specific error reason.
GetAliasByTopicName
Retrieves the topic alias if defined for the given topic name. Returns 0 if no alias is set.

Parameters

const char* topicName The topic name for which to retrieve the alias.

Return Value

The alias (a word) for the specified topic name. Returns 0 if none is found.
GetNameByTopicAlias
Retrieves the topic name for the given topic alias if available.

Parameters

word alias The alias for which to retrieve the topic name.

Return Value

The topic name (const char*) or nullptr if no name is found for the alias.

UMqttClient

class UMqttClient {
public:
    virtual ~UMqttClient() = default;

    virtual void MQTTClientConnectComplete(IMqttClient* const mqttClient,
                                           const MqttConnectAckInfo& info) = 0;

    virtual void MQTTClientConnectFail(IMqttClient* const mqttClient,
                                       MQTTReasonCode reasonCode,
                                       const char* reasonString) = 0;

    virtual void MQTTClientDisconnect(IMqttClient* const mqttClient,
                                      MQTTReasonCode reasonCode) = 0;

    virtual void MQTTClientSubscribeComplete(IMqttClient* const mqttClient,
                                             const char* topic,
                                             const MqttUserProperty& userProperty) = 0;

    virtual void MQTTClientSubscribeFail(IMqttClient* const mqttClient,
                                         const char* topic,
                                         MQTTReasonCode reasonCode) = 0;

    virtual void MQTTClientPublishRecv(IMqttClient* const mqttClient,
                                       const MqttPublishRecvInfo& info) = 0;

    virtual void MQTTClientUnsubscribeComplete(IMqttClient* const mqttClient,
                                               const char* topic,
                                               const MqttUserProperty& userProperty) = 0;

    virtual void MQTTClientUnsubscribeFail(IMqttClient* const mqttClient,
                                           const char* topic,
                                           MQTTReasonCode reasonCode) = 0;

    virtual void MQTTClientPublishComplete(IMqttClient* const mqttClient,
                                           const MqttPublishCompleteInfo& info) = 0;

    virtual void MQTTClientPublishFail(IMqttClient* const mqttClient,
                                       MQTTReasonCode reasonCode) = 0;

    virtual void MQTTClientPingComplete(IMqttClient* const mqttClient) = 0;

    virtual void MQTTClientAuthenticate(IMqttClient* const mqttClient,
                                        MQTTReasonCode reasonCode) = 0;

    virtual void MQTTClientError(IMqttClient* const mqttClient,
                                 MqttError reason) = 0;
};

This class is for receiving callbacks from the IMqttClient. You must pass a subclass of UMqttClient to an IMqttClient as user in order to handle events such as connection completion, disconnection, subscription success/failure, publish completion, incoming messages, errors, etc.

Callback functions

MQTTClientConnectComplete
Called when the connection to the broker completes successfully. All CONNACK details are provided in a MqttConnectAckInfo struct (session flag, expiry interval, receive maximum, max QoS, assigned client ID, topic alias max, etc.).
MQTTClientConnectFail
Called if the connection to the broker cannot be established or is rejected by the broker.
MQTTClientDisconnect
Called after a normal or abnormal disconnection from the broker.
MQTTClientSubscribeComplete
Called after a successful subscription. The optional user property returned by the broker is provided as a MqttUserProperty.
MQTTClientSubscribeFail
Called if subscribing to a topic (or multiple topics) fails.
MQTTClientPublishRecv
Called when a PUBLISH message is received for a subscribed topic. All message details (topic, payload, QoS, retain flag, topic alias, content type, expiry interval, response topic, correlation data, subscription identifier, and user property) are provided in a MqttPublishRecvInfo struct.
MQTTClientUnsubscribeComplete
Called after successfully unsubscribing from a topic. The optional user property returned by the broker is provided as a MqttUserProperty.
MQTTClientUnsubscribeFail
Called when unsubscribing fails.
MQTTClientPublishComplete
Called after a PUBLISH operation completes (e.g., after receiving PUBACK/PUBCOMP for QoS > 0). The QoS level and optional user property are provided in a MqttPublishCompleteInfo struct.
MQTTClientPublishFail
Called if a publish operation fails.
MQTTClientPingComplete
Called after a PINGREQ/PINGRESP cycle completes successfully.
MQTTClientAuthenticate
Called if enhanced auth is in progress and the broker sends an AUTH packet. The client can respond by calling MQTTSendAuthData.
MQTTClientError
Called if there is an internal error on the client side (e.g., malformed packet).

Data types

MqttError

enum MqttError {
    Success = 0,
    WrongPacketType,
    Malformed,
    BufferAllocationFailed,
    NullBufferRecived,
    MaxBinDataExceeded,
    StringSizeExceeded,
    VariableHeaderError,
    PayloadError,
    FlagSetButNoTopic,
    FlagSetButNoPayload,
    FlagSetButNoUserName,
    FlagSetButNoPassword,
    EmptyData,
    IndexOutOfRange,
    SubscriptionIdentifierMissing,
    IncorrectValue,
    NoConnectionEstablished,
    UnspecifierError,
    PacketTooLarge,
    StringTooLarge,
    OutputBufferToSmall,
    InputClientIdIncorrect,
    RetainNotSupportedByBroker,
    TopicAliasNonExistant,
    TopicAliasNotSupported,
    TopicAliasUnavailable,
    InvalidTopicName,
    NotAuthorized
};

MqttError defines client-side error conditions during MQTT operations (e.g., Malformed, IncorrectValue).

MQTTReasonCode

enum MQTTReasonCode {
    SUCCESS = 0x00,
    NORMAL_DISCONNECTION = 0x00,
    GRANTED_QOS0 = 0x00,
    GRANTED_QOS1 = 0x01,
    GRANTED_QOS2 = 0x02,
    DISCONNECT_WITH_WILL_MESSAGE = 0x04,
    NO_MATCHING_SUBSCRIBERS = 0x10,
    NO_SUBSCRIPTION_EXISTED = 0x11,
    CONTINUE_AUTHENTICATION = 0x18,
    RE_AUTHENTICATE = 0x19,
    UNSPECIFIED_ERROR = 0x80,
    MALFORMED_PACKET = 0x81,
    PROTOCOL_ERROR = 0x82,
    IMPLEMENTATION_SPECIFIC_ERROR = 0x83,
    UNSUPPORTED_PROTOCOL_VERSION = 0x84,
    CLIENT_IDENTIFIER_NOT_VALID = 0x85,
    BAD_USER_NAME_OR_PASSWORD = 0x86,
    NOT_AUTHORIZED = 0x87,
    SERVER_UNAVAILABLE = 0x88,
    SERVER_BUSY = 0x89,
    BANNED = 0x8A,
    SERVER_SHUTTING_DOWN = 0x8B,
    BAD_AUTHENTICATION_METHOD = 0x8C,
    KEEP_ALIVE_TIMEOUT = 0x8D,
    SESSION_TAKEN_OVER = 0x8E,
    TOPIC_FILTER_INVALID = 0x8F,
    TOPIC_NAME_INVALID = 0x90,
    PACKET_IDENTIFIER_IN_USE = 0x91,
    PACKET_IDENTIFIER_NOT_FOUND = 0x92,
    RECEIVE_MAXIMUM_EXCEEDED = 0x93,
    TOPIC_ALIAS_INVALID = 0x94,
    PACKET_TOO_LARGE = 0x95,
    MESSAGE_RATE_TOO_HIGH = 0x96,
    QUOTA_EXCEEDED = 0x97,
    ADMINISTRATIVE_ACTION = 0x98,
    PAYLOAD_FORMAT_INVALID = 0x99,
    RETAIN_NOT_SUPPORTED = 0x9A,
    QOS_NOT_SUPPORTED = 0x9B,
    USE_ANOTHER_SERVER = 0x9C,
    SERVER_MOVED = 0x9D,
    SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 0x9E,
    CONNECTION_RATE_EXCEEDED = 0x9F,
    MAXIMUM_CONNECT_TIME = 0xA0,
    SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 0xA1,
    WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 0xA2
};

MQTTReasonCode enumerates the possible reason codes in MQTT for connection, disconnection, and other operations. Reason Codes .

MQTTAuthReasonCode

enum MQTTAuthReasonCode {
    ContinueAuthentication = 0x18,
    Reauthenticate = 0x19
};

MQTTClientDisconnectReason

enum MQTTClientDisconnectReason {
    NormalDisconnection = 0x00,
};

MQTTClientDisconnectReason indicates the reason for disconnecting. NormalDisconnection (0x00) is used for a graceful disconnect.

Structs

MqttUserProperty

struct MqttUserProperty {
    const char* name  = nullptr;
    const char* value = nullptr;
};

Represents a single MQTT user property as a name/value pair. Both fields can be comma-separated strings to pass multiple properties in one call. Used in most API functions and callbacks.

MqttConnectCredentials

struct MqttConnectCredentials {
    const char* userName     = nullptr;
    const byte* password     = nullptr;
    word        passwordSize = 0;
};

Groups the username and binary password for MQTT authentication. Embedded in MqttConnectOptions.

MqttWillOptions

struct MqttWillOptions {
    const char* topic                  = nullptr;
    const byte* payload                = nullptr;
    word        payloadSize            = 0;
    byte        qos                    = 0;
    bool        retain                 = false;
    dword       delayInterval          = 0;
    bool        payloadFormatIndicator = false;
    dword       messageExpiryInterval  = 0;
    const char* contentType            = nullptr;
    const char* responseTopic          = nullptr;
    const byte* correlationData        = nullptr;
    word        correlationDataSize    = 0;
    MqttUserProperty userProperty      = {};
};

Groups all Last Will and Testament (LWT) parameters. If topic and payload are set, the Will flag is set automatically. Embedded in MqttConnectOptions.

MqttConnectOptions

struct MqttConnectOptions {
    word        port                       = 1883;
    bool        tls                        = false;
    word        keepAlive                  = 0;
    dword       sessionExpiryInterval      = 0;
    const char* authenticationMethod       = nullptr;
    const byte* authenticationData         = nullptr;
    word        authenticationDataSize     = 0;
    word        receiveMaximum             = 65535;
    dword       maximumPacketSize          = 65535;
    word        topicAliasMaximum          = 0;
    bool        requestResponseInformation = false;
    bool        requestProblemInformation  = true;
    MqttUserProperty       userProperty    = {};
    MqttConnectCredentials credentials     = {};
    MqttWillOptions        will            = {};
};

Groups all optional parameters for MQTTConnect. All fields have sensible defaults so only the relevant fields need to be set.

MqttSubscribeOptions

struct MqttSubscribeOptions {
    const char* qosLevels           = nullptr;
    const char* noLocalFlags        = nullptr;
    const char* retainFlags         = nullptr;
    const char* retainHandlingFlags = nullptr;
};

Groups the per-topic subscription flags for MQTTSubscribe. Each field is a comma-separated string matching the topic order, e.g. qosLevels = "0,2" for two topics with QoS 0 and 2 respectively.

MqttPublishOptions

struct MqttPublishOptions {
    byte        qos                   = 0;
    word        topicAlias            = 0;
    const byte* payload               = nullptr;
    size_t      payloadSize           = 0;
    const char* contentType           = nullptr;
    bool        retain                = false;
    MqttUserProperty userProperty     = {};
    dword       messageExpiryInterval = 0;
    const char* responseTopic         = nullptr;
    const byte* correlationData       = nullptr;
    word        correlationDataSize   = 0;
};

Groups all optional parameters for MQTTPublish. Set topicAlias to assign or reuse a topic alias (see the MQTT v5 spec for details).

MqttDisconnectOptions

struct MqttDisconnectOptions {
    MQTTClientDisconnectReason reason              = NormalDisconnection;
    dword                      sessionExpiryInterval = 0;
    const char*                reasonString        = nullptr;
    MqttUserProperty           userProperty        = {};
    const char*                serverReference     = nullptr;
};

Groups all optional parameters for MQTTDisconnect.

MqttAuthOptions

struct MqttAuthOptions {
    MQTTAuthReasonCode reasonCode   = MQTTAuthReasonCode::ContinueAuthentication;
    const char*        reasonString = nullptr;
    MqttUserProperty   userProperty = {};
};

Groups the optional parameters for MQTTSendAuthData.

MqttConnectAckInfo

struct MqttConnectAckInfo {
    bool        isNewSession               = false;
    dword       sessionExpiryInterval      = 0;
    word        receiveMaximum             = 0;
    byte        maxQoS                     = 0;
    byte        retainAvailable            = 0;
    dword       maxPacketSize              = 0;
    const char* clientId                   = nullptr;
    dword       topicAliasMax              = 0;
    MqttUserProperty userProperty          = {};
    byte        wildCardAvailable          = 0;
    byte        sharedSubscriptionAvailable = 0;
    dword       serverKeepAlive            = 0;
};

Carries all fields from the broker's CONNACK packet. Passed to MQTTClientConnectComplete.

MqttPublishRecvInfo

struct MqttPublishRecvInfo {
    const char* topic                  = nullptr;
    const char* msg                    = nullptr;
    size_t      msgLen                 = 0;
    word        subscriptionIdentifier = 0;
    MqttUserProperty userProperty      = {};
    byte        qos                    = 0;
    word        topicAlias             = 0;
    const char* contentType            = nullptr;
    bool        retain                 = false;
    dword       messageExpiryInterval  = 0;
    const char* responseTopic          = nullptr;
    const byte* correlationData        = nullptr;
    word        correlationDataSize    = 0;
};

Carries all fields of an incoming PUBLISH packet. Passed to MQTTClientPublishRecv.

MqttPublishCompleteInfo

struct MqttPublishCompleteInfo {
    byte             qos          = 0;
    MqttUserProperty userProperty = {};
};

Carries the QoS level and optional user property of a completed publish operation. Passed to MQTTClientPublishComplete.

Code Example

Prerequisites: Setting up the innovaphone MQTT Broker

This example connects to a local innovaphone MQTT broker. Before running the code, ensure the broker is installed and the instance is running:

  1. Open the innovaphone App Platform in your browser and navigate to the Apps section.
  2. Install the MQTT Broker app from the app store if it is not already present.
  3. Create a new instance of the MQTT Broker app. Give it a name (e.g., mqtt) and confirm the configuration.
  4. Start the instance and verify that it is in the Running state in the App Platform dashboard.
  5. Note the hostname or IP address of your innovaphone device. The broker listens on port 1883 (plain TCP) by default. No credentials are required for a local connection unless configured otherwise in the instance settings.

Once the broker instance is running, the client code below can connect to it directly using the device's hostname or IP address.

Example Code

The following example connects to the local innovaphone MQTT broker, subscribes to a wildcard topic, and publishes messages:

void TaskMqttTest::Start(UTask* user) {
    const char* brokerHost = "192.168.1.1"; // Replace with your innovaphone device address

    client = IMqttClient::Create(instance->GetIIoMux(),
                                 instance->GetTcpSocketProvider(),
                                 instance->GetTlsSocketProvider(),
                                 this,
                                 instance->GetLog(),
                                 dns->Create(instance->GetIIoMux()));

    // If generating a client ID, ensure the buffer is at least 24 bytes
    // (23-byte generated ID plus null terminator).
    char generatedClientIdBuffer[24];

    MqttConnectOptions options;
    options.keepAlive = 60; // 60 seconds

    MqttError state = client->MQTTConnect(brokerHost,
                                          generatedClientIdBuffer,
                                          sizeof(generatedClientIdBuffer),
                                          nullptr, // generate client ID
                                          options);
    if (state) {
        printf("MQTTConnect error: %d", state);
    }
}

void TaskMqttTest::MQTTClientConnectComplete(IMqttClient* const mqttClient,
                                             const MqttConnectAckInfo& info)
{
    // Send a ping to verify the broker is responsive.
    client->MQTTPing();

    // Subscribe to all topics using the wildcard '#', QoS 0.
    // Subscription identifier 12 is stored by the application to correlate incoming messages.
    MqttSubscribeOptions subOptions;
    subOptions.qosLevels = "0";
    client->MQTTSubscribe(12, "#", subOptions);

    // Publish an initial message to test/light1.
    MqttPublishOptions pubOptions;
    pubOptions.payload     = (byte*)"innoClient MQTT5";
    pubOptions.payloadSize = strlen("innoClient MQTT5");
    client->MQTTPublish("test/light1", pubOptions);
}

void TaskMqttTest::MQTTClientDisconnect(IMqttClient* const mqttClient, MQTTReasonCode reasonCode)
{
    printf("Disconnected with reason: %x", reasonCode);
}

void TaskMqttTest::MQTTClientConnectFail(IMqttClient* const mqttClient,
                                         MQTTReasonCode reasonCode, const char* reasonString)
{
    printf("Connect failed, reason: %x", reasonCode);
}

void TaskMqttTest::MQTTClientPublishRecv(IMqttClient* const mqttClient,
                                         const MqttPublishRecvInfo& info)
{
    printf("Message received on topic: %s", info.topic);
    if (!strcmp(info.topic, "test/light2") && info.subscriptionIdentifier == 12) {
        MqttPublishOptions pubOptions;
        pubOptions.payload     = (byte*)"Next message from innoClient";
        pubOptions.payloadSize = strlen("Next message from innoClient");
        client->MQTTPublish("test/light1", pubOptions);
    }
    else {
        printf("%.*s", (int)info.msgLen, info.msg);
    }
}

void TaskMqttTest::MQTTClientPublishComplete(IMqttClient* const mqttClient,
                                             const MqttPublishCompleteInfo& info)
{
    printf("Publish completed for QoS %d.", (int)info.qos);
}

void TaskMqttTest::MQTTClientUnsubscribeComplete(IMqttClient* const mqttClient, const char* topic,
                                                 const MqttUserProperty& userProperty)
{
    printf("Unsubscribed from topic: %s", topic);
}

void TaskMqttTest::MQTTClientUnsubscribeFail(IMqttClient* const mqttClient, const char* topic,
                                             MQTTReasonCode reasonCode)
{
    printf("Unsubscribe failed for topic: %s, reason: %x", topic, reasonCode);
}

void TaskMqttTest::MQTTClientPingComplete(IMqttClient* const mqttClient)
{
    printf("Ping response received.");
}

void TaskMqttTest::MQTTClientSubscribeComplete(IMqttClient* const mqttClient, const char* topic,
                                               const MqttUserProperty& userProperty)
{
    printf("Subscribed to topic: %s", topic);
}

void TaskMqttTest::MQTTClientSubscribeFail(IMqttClient* const mqttClient, const char* topic,
                                           MQTTReasonCode reasonCode)
{
    printf("Subscribe failed for topic: %s, reason: %x", topic, reasonCode);
}