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