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

Examples Code Example

Functions

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,
                                  word port = 1883,
                                  bool tls = false,
                                  const char* payloadUserName = nullptr,
                                  const byte* payloadPassword = nullptr,
                                  word payloadPasswordSize = 0,
                                  const char* inputClientId = nullptr,
                                  word keepAlive = 0,
                                  const char* willTopic = nullptr,
                                  const byte* willPayload = nullptr,
                                  word willPayloadSize = 0,
                                  byte willQoS = 0,
                                  bool willRetain = false,
                                  const char* userPropertyName = nullptr,
                                  const char* userPropertyValue = nullptr,
                                  dword sessionExpiryInterval = 0,
                                  const char* authenticationMethod = nullptr,
                                  const byte* authenticationData = nullptr,
                                  word authenticationDataSize = 0,
                                  word reciveMaximum = 65535,
                                  dword maximumPacketSize = 65535,
                                  word topicAliasMaximum = 0,
                                  bool requestResponseInformation = 0,
                                  bool requestProblemInformation = 1,
                                  dword willDelayInterval = 0,
                                  bool payloadFormatIndicator = 0,
                                  dword messageExpiryInterval = 0,
                                  const char* contentType = nullptr,
                                  const char* responseTopic = nullptr,
                                  const byte* correlationData = nullptr,
                                  word correlationDataSize = 0,
                                  const char* payloadUserPropertyName = nullptr,
                                  const char* payloadUserPropertyValue = nullptr) = 0;

    virtual MqttError MQTTSubscribe(word subscriptionIdentifier,
                                    const char* topicFilter,
                                    const char* qosLevels = nullptr,
                                    const char* noLocalFlags = nullptr,
                                    const char* retainFlags = nullptr,
                                    const char* retainHandlingFlags = nullptr) = 0;

    virtual MqttError MQTTPublish(const char* topicName,
                                  byte QoS = 0,
                                  word topicAlias = 0,
                                  const byte* payload = nullptr,
                                  size_t payloadSize = 0,
                                  const char* contentType = nullptr,
                                  bool retain = false,
                                  const char* userPropertyName = nullptr,
                                  const char* userPropertyValue = nullptr,
                                  dword messageExpiryInterval = 0,
                                  const char* responseTopic = nullptr,
                                  const byte* correlationData = nullptr,
                                  word correlationDataSize = 0) = 0;

    virtual MqttError MQTTUnsubscribe(const char* topicFilter,
                                      const char* userPropertyName = nullptr,
                                      const char* userPropertyValue = nullptr) = 0;

    virtual MqttError MQTTPing() = 0;

    virtual MqttError MQTTDisconnect(MQTTClientDisconnectReason reason = NormalDisconnection,
                                     dword sessionExpiryInterval = 0,
                                     const char* reasonString = nullptr,
                                     const char* userPropertyname = nullptr,
                                     const char* userPropertyValue = nullptr,
                                     const char* serverReference = nullptr) = 0;

    virtual MqttError MQTTSendAuthData(const char* authenticationMethod,
                                       const byte* authenticationData,
                                       word authenticationDataSize,
                                       MQTTAuthReasonCode reasonCode = MQTTAuthReasonCode::ContinueAuthentication,
                                       const char* reasonString = nullptr,
                                       const char* userPropertyName = nullptr,
                                       const char* userPropertyValue = nullptr) = 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.

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. 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 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 using the given parameters. If the broker is secured (TLS), set tls to true and connect to the corresponding port (e.g., 8883).

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.
size_t outputClientIdSize Size of the outputClientId buffer.
word port (Default: 1883) The port number for MQTT connection. Typical default for TLS is 8883.
bool tls (Default: false) Set to true to enable TLS connection.
const char* payloadUserName (Default: nullptr) The username for MQTT connection (if any).
const byte* payloadPassword (Default: nullptr) The password as binary data (if any).
word payloadPasswordSize (Default: 0) The size of the binary password buffer.
const char* inputClientId (Default: nullptr) If specified, the client ID used for the MQTT connection. If null, a client ID may be generated.
word keepAlive (Default: 0) MQTT keep-alive interval in seconds (0 means no keep-alive required).
const char* willTopic (Default: nullptr) The topic for the Last Will and Testament message.
const byte* willPayload (Default: nullptr) The payload for the Last Will message.
word willPayloadSize (Default: 0) The size of the Will message payload.
byte willQoS (Default: 0) QoS level for Will message (0, 1, or 2).
bool willRetain (Default: false) If true, the Will message is retained by the broker.
const char* userPropertyName (Default: nullptr) Optional user property name.
const char* userPropertyValue (Default: nullptr) Optional user property value.
dword sessionExpiryInterval (Default: 0) The session expiry interval for the connection (0 means no session expiry).
const char* authenticationMethod (Default: nullptr) The authentication method.
const byte* authenticationData (Default: nullptr) Binary authentication data.
word authenticationDataSize (Default: 0) The size of the authentication data.
word reciveMaximum (Default: 65535) The receive maximum for inbound QoS 1 or 2 publishes.
dword maximumPacketSize (Default: 65535) The maximum packet size the client is willing to accept.
word topicAliasMaximum (Default: 0) The max number of aliases the client supports.
bool requestResponseInformation (Default: 0) If true, the server should return response information.
bool requestProblemInformation (Default: 1) If false, the server may reduce the amount of error information returned.
dword willDelayInterval (Default: 0) The delay (in seconds) before the broker publishes the Will message.
bool payloadFormatIndicator (Default: 0) Indicates the format of the Will message payload (UTF-8 or binary).
dword messageExpiryInterval (Default: 0) How long a message is stored by the broker (in seconds).
const char* contentType (Default: nullptr) The content type of the Will message payload.
const char* responseTopic (Default: nullptr) A topic to direct responses to for request/response scenarios.
const byte* correlationData (Default: nullptr) Used by request/response to correlate the request and response messages.
word correlationDataSize (Default: 0) The size of the correlation data.
const char* payloadUserPropertyName (Default: nullptr) An optional user property name for the Will message.
const char* payloadUserPropertyValue (Default: nullptr) An optional user property value for the Will message.

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 can be specified with a similarly comma-separated list, e.g. "0, 2", to match the topics in order.

Parameters

word 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 char * qosLevels (Default: nullptr) A comma-separated string for QoS levels corresponding to each topic, e.g. "0,1".
const char * noLocalFlags (Default: nullptr) If used, a comma-separated string describing whether No Local is set (0 or 1) for each subscription.
const char * retainFlags (Default: nullptr) A comma-separated string describing if Retain As Published is set (0 or 1) for each subscription.
const char * retainHandlingFlags (Default: nullptr) A comma-separated string describing how retained messages are handled on subscribe (0,1,2) for each topic.

Return Value

An MqttError indicating success or a specific error reason.
MQTTPublish
Publishes a message to one or multiple topics. Topics can be comma-separated, and matching QoS must be comma-separated if multiple are used.

Parameters

const char * topicName The topic(s) to publish to, separated by commas if more than one.
byte QoS (Default: 0) QoS level (0, 1, or 2). Can be comma-separated if multiple topics are given.
word topicAlias (Default: 0) A topic alias if supported. Use 0 if no alias is used.
const byte* payload (Default: nullptr) Pointer to the binary data to send as payload.
size_t payloadSize (Default: 0) The length of the payload data.
const char* contentType (Default: nullptr) Content type of the message payload.
bool retain (Default: false) If true, the broker retains the message.
const char* userPropertyName (Default: nullptr) An optional user property name (can be comma-separated if multiple are used).
const char* userPropertyValue (Default: nullptr) An optional user property value (comma-separated, matching the name list in order).
dword messageExpiryInterval (Default: 0) The time in seconds after which the broker will drop the message if not delivered.
const char* responseTopic (Default: nullptr) A topic to direct responses to for request/response scenarios.
const byte* correlationData (Default: nullptr) Binary data used to correlate request/response messages.
word correlationDataSize (Default: 0) The size of the correlation data.

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 char* userPropertyName (Default: nullptr) An optional user property name, can be comma-separated if multiple are used.
const char* userPropertyValue (Default: nullptr) An optional user property value, can be comma-separated, matching the names in order.

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 with an optional reason code and additional data.

Parameters

MQTTClientDisconnectReason reason (Default: NormalDisconnection) The disconnection reason code.
dword sessionExpiryInterval (Default: 0) The session expiry interval the client wants to set on disconnect.
const char* reasonString (Default: nullptr) A human-readable reason string.
const char* userPropertyname (Default: nullptr) A user property name.
const char* userPropertyValue (Default: nullptr) A user property value.
const char* serverReference (Default: nullptr) An optional server reference, e.g., used by the broker for redirection.

Return Value

An MqttError indicating success or a specific error reason.
MQTTSendAuthData
Sends authentication data to the broker if needed (enhanced authentication).

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.
MQTTAuthReasonCode reasonCode (Default: ContinueAuthentication) The reason code for sending the auth packet.
const char* reasonString (Default: nullptr) An optional human-readable string describing the reason.
const char* userPropertyName (Default: nullptr) A user property name (comma-separated if more than one).
const char* userPropertyValue (Default: nullptr) A user property value (comma-separated, matching names).

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:
    ~UMqttClient() {}

    virtual void MQTTClientConnectComplete(IMqttClient* const mqttClient, 
                                           bool isNewSession,
                                           dword sessionExpiryInterval,
                                           word receiveMaximum,
                                           byte maxQoS,
                                           byte retainAvailable,
                                           dword maxPacketSize,
                                           const char* clientId,
                                           dword topicAliasMax,
                                           const char* userPropertyName,
                                           const char* userPropertyValue,
                                           byte wildCardAvailable,
                                           byte sharedSubscriptionAvailable,
                                           dword serverKeepAlive) = 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 char* userPropertyName,
                                             const char* userPropertyValue) = 0;

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

    virtual void MQTTClientPublishRecv(IMqttClient* const mqttClient,
                                       const char* topic,
                                       const char* msg,
                                       size_t msg_len,
                                       word subscriptionIdentifier,
                                       const char* userPropertyName,
                                       const char* userPropertyValue) = 0;

    virtual void MQTTClientUnsubscribeComplete(IMqttClient* const mqttClient,
                                               const char* topic,
                                               const char* userPropertyName,
                                               const char* userPropertyValue) = 0;

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

    virtual void MQTTClientPublishComplete(IMqttClient* const mqttClient,
                                           const byte QoS,
                                           const char* userPropertyName,
                                           const char* userPropertyValue) = 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. The parameters provide details from the CONNACK such as whether it's a new session, session expiry, 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 to a topic or multiple topics.
MQTTClientSubscribeFail
Called if subscribing to a topic (or multiple topics) fails.
MQTTClientPublishRecv
Called when a PUBLISH message is received for a subscribed topic.
MQTTClientUnsubscribeComplete
Called after successfully unsubscribing from a topic.
MQTTClientUnsubscribeFail
Called when unsubscribing fails.
MQTTClientPublishComplete
Called after a PUBLISH operation completes (e.g., after receiving PUBACK/PUBCOMP for QoS > 0).
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
};

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.

Code Example

Below is an example of connecting to a TLS broker on HiveMQ, showing how to generate a client ID (if needed), subscribe to multiple topics, and publish messages:

void TaskMqttTest::Start(UTask* user) {
    // Note: This is an example to connect to a TLS broker from HiveMQ.
    // Login data is anonymized here.
    const char* username = "mqttUser";
    byte* password = (byte*)"mqttPass";
    word keepAlive = 60;                // 60 seconds
    word port = 8883;
    // Example: we can create the client with the needed arguments:
    client = IMqttClient::Create(instance->GetIIoMux(), 
                                 instance->GetTcpSocketProvider(), 
                                 instance->GetTlsSocketProvider(), 
                                 this, 
                                 instance->GetLog(), 
                                 dns->Create(instance->GetIIoMux()));

    // If generating an ID, ensure 24 bytes are allocated for the 23-byte ID plus null terminator
    char* generatedClientIdBuffer = (char*) malloc(24); 
    size_t bufferSize = 24; // For illustration

    // Connect to the TLS broker at port 8883:
    MqttError state = client->MQTTConnect("example.hivemq.cloud", 
                                          generatedClientIdBuffer, // outputClientId
                                          bufferSize,              // outputClientIdSize
                                          port,
                                          true,                    // TLS
                                          username,                // payloadUserName
                                          password,                // payloadPassword
                                          strlen((char*)password), // payloadPasswordSize
                                          nullptr,                 // inputClientId
                                          keepAlive);              
    if (state) {
        printf("ERROR");
    }
}

void TaskMqttTest::MQTTClientConnectComplete(IMqttClient* const mqttClient, bool isNewSession, 
                                             dword sessionExpiryInterval, word receiveMaximum, 
                                             byte maxQoS, byte retainAvailable, dword maxPacketSize,
                                             const char* clientId, dword topicAliasMax, 
                                             const char* userPropertyName, const char* userPropertyValue, 
                                             byte wildCardAvailable, byte sharedSubscriptionAvailable, 
                                             dword serverKeepAlive) 
{
    // For example, send a ping and subscribe to a wildcard topic:
    client->MQTTPing();
    // Subscribing with subscription identifier 12, topic "#", QoS "0"
    client->MQTTSubscribe(12, "#", "0");

    // Now publish a message to test/light1
    byte* payload = (byte*)"innoClient MQTT5";
    client->MQTTPublish("test/light1", 0, 0, payload, strlen((char*)payload));
}

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");
}

void TaskMqttTest::MQTTClientPublishRecv(IMqttClient* const mqttClient, const char* topic, const char* msg, size_t msg_len, word subscriptionIdentifier,
                                         const char* userPropertyName, const char* userPropertyValue) 
{
    printf("RECIVED NEW MESSAGE");
    if (!strcmp(topic, "test/light2")) {
        if (subscriptionIdentifier == 12) {
            byte* payload = (byte*)"Next Message from innoClient";
            client->MQTTPublish("test/light1", 0, 0, payload, strlen((char*)payload));
        }
    }
    else {
        printf("%s", msg);
    }
}

void TaskMqttTest::MQTTClientPublishComplete(IMqttClient* const mqttClient, const byte QoS,  const char* userPropertyName, const char* userPropertyValue) 
{
    printf("Publish completed.");
}

void TaskMqttTest::MQTTClientUnsubscribeComplete(IMqttClient* const mqttClient, const char* topic, const char* userPropertyName, const char* userPropertyValue) 
{
    printf("Unsubscribe TOPIC: %s", topic);
}

void TaskMqttTest::MQTTClientUnsubscribeFail(IMqttClient* const mqttClient, const char* topic, MQTTReasonCode reasonCode) 
{
    printf("Failed to Subscribe/Unsubscribe to: %s with ReasonCode:%x", topic, reasonCode);
}

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

void TaskMqttTest::MQTTClientSubscribeComplete(IMqttClient* const mqttClient, const char* topic,  const char* userPropertyName, const char* userPropertyValue) 
{
    printf("Subscribed to TOPIC: %s", topic);
    // If we subscribed to multiple topics: "test/light1, test/light2" with QoS "0,2" 
    // we can do further actions here.
    if (!strcmp(topic, "test/light1, test/light2")) {
        byte* payload = (byte*)"inno Client";
        // Example publish with QoS 2
        client->MQTTPublish("test/light1", 2, 0, payload, strlen((char*)payload));
    }
}