MQTT

struct mg_mqtt_opts

struct mg_mqtt_opts {
  struct mg_str user;               // Username, can be empty
  struct mg_str pass;               // Password, can be empty
  struct mg_str client_id;          // Client ID
  struct mg_str topic;              // message/subscription topic
  struct mg_str message;            // message content
  uint8_t qos;                      // message quality of service
  uint8_t version;                  // Can be 4 (3.1.1), or 5. If 0, assume 4
  uint16_t keepalive;               // Keep-alive timer in seconds
  uint16_t retransmit_id;           // For PUBLISH, init to 0
  bool retain;                      // Retain flag
  bool clean;                       // Clean session flag
  struct mg_mqtt_prop *props;       // MQTT5 props array
  size_t num_props;                 // number of props
  struct mg_mqtt_prop *will_props;  // Valid only for CONNECT packet (MQTT5)
  size_t num_will_props;            // Number of will props
};

Structure used when connecting to a broker and when sending messages, to specify connection options and last-will message or to specify message and options

struct mg_mqtt_message

struct mg_mqtt_message {
  struct mg_str topic;  // Parsed topic for PUBLISH
  struct mg_str data;   // Parsed message for PUBLISH
  struct mg_str dgram;  // Whole MQTT packet, including headers
  uint16_t id;          // For PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH
  uint8_t cmd;          // MQTT command, one of MQTT_CMD_*
  uint8_t qos;          // Quality of service
  uint8_t ack;          // CONNACK return code, 0 = success
  size_t props_start;   // Offset to the start of the properties (MQTT5)
  size_t props_size;    // Length of the properties
};

Structure representing an MQTT packet, either control or data

mg_mqtt_connect()

struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
                                      const struct mg_mqtt_opts *opts,
                                      mg_event_handler_t fn, void *fn_data);

Create a client MQTT connection

Parameters:

  • mgr - Event manager to use
  • url - Specifies the broker URL, e.g. mqtt://cloud.hivemq.com. If this URL is 'mqtts', the is_tls flag will be set
  • opts - pointer to MQTT options like client ID, clean session, last will, etc. Can be NULL
  • fn - The event handler function
  • fn_data - an arbitrary pointer, which will be stored in the connection structure as c->fn_data, so the event handler can use it when called.

Return value: created connection, or NULL on error. Possible errors are: not enough memory, a NULL URL, or, in the case of our built-in TCP/IP stack, the network not being ready.

Note: This function does not connect to a broker; it allocates the required resources and starts the TCP connection process. Once that connection is established, an MG_EV_CONNECT event is sent to the connection event handler, then the MQTT connection process is started (by means of mg_mqtt_login()); and once the MQTT connection request gets a response from the broker, an MG_EV_MQTT_OPEN event is sent to the connection event handler; connection results are inside a struct mg_mqtt_message

Usage example:

void fn(struct mg_connection *c, int ev, void *evd, void *fnd) {
  if (ev == MG_EV_CONNECT) {
    // TCP connection succeeded,
    // If target URL is TLS, set it up
  } else if (ev == MG_EV_MQTT_OPEN) {
    // MQTT connection process finished
    struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
    if(mm->ack)  // MQTT connection succeeded
  }
}
mg_mqtt_connect(&mgr, "mqtt://test.org:1883", NULL, fn, NULL);

or

struct mg_mqtt_opts opts = {.qos = 1,
                            .retain = true,
                            .topic = mg_str("mytopic"),
                            .message = mg_str("goodbye")};
mg_mqtt_connect(&mgr, "mqtt://test.org:1883", &opts, fn, NULL);

mg_mqtt_listen()

struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
                                     mg_event_handler_t fn, void *fn_data);

Create an MQTT listener (act like a broker).

Parameters:

  • mgr - Event manager to use
  • url - Specifies the local IP address and port to listen on, e.g. mqtt://0.0.0.0:1883. If this URL is 'mqtts', the is_tls flag will be set
  • fn - The event handler function
  • fn_data - an arbitrary pointer, which will be stored in the connection structure as c->fn_data, so the event handler can use it when called.

Return value: Pointer to the created connection or NULL on error

Usage example:

struct mg_connection *c = mg_mqtt_listen(&mgr, "mqtt://0.0.0.0:1883", fn, arg);
if (c == NULL) return -1; // Could not create connection

mg_mqtt_login()

void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);

Send MQTT CONNECT request. Once the MQTT connection request gets a response from the broker, an MG_EV_MQTT_OPEN event is sent to the connection event handler. This function is usually called by mg_mqtt_connect(), you will only need to call it when you manually start the MQTT connect process, e.g: when using MQTT over WebSocket. Connection results are inside a struct mg_mqtt_message

Parameters:

  • c - Connection to use
  • opts - pointer to MQTT connect options, containing user name and password to use, if any, and other options

Return value: None

Usage example:

// Mongoose event handler
void fn(struct mg_connection *c, int ev, void *evd, void *fnd) {
  if (ev == MG_EV_WS_OPEN) {
    // WS connection established. Perform MQTT login
    struct mg_mqtt_opts opts = {.qos = 1,
                                .retain = true,
                                .topic = mg_str("mytopic"),
                                .message = mg_str("goodbye")};
    mg_mqtt_login(c, &opts);
  } else if (ev == MG_EV_MQTT_OPEN) {
    // MQTT connection process finished
    struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
    if(mm->ack)  // MQTT connection succeeded
  }
}

mg_mqtt_pub()

uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);

Publish a message to a specified topic, each contained in a struct msg_str

Note: This function does not actually send the message, it delivers to the underlying TCP/IP stack which will be checked later when the manager runs.

Note that Mongoose does not handle retries for QoS 1 and 2. That has to be handled by the application in the event handler, if needed. You can check if a publish request with QoS 1 or 2 succeeded by catching MG_EV_MQTT_CMD events and checking for reception of PUBACK/PUBREC and PUBCOMP messsages; and their result codes inside a struct mg_mqtt_message

Parameters:

  • c - Connection to use
  • opts - pointer to publish MQTT options, like QoS, and retain flag. The message body is expected at opts->message, the topic at opts->topic; both as mg_str

Return value: When using QoS other than 0, this function returns the id field sent to the broker, suitable to be held in opts->retransmit_id for a possible retransmission. See this tutorial. Discard the returned value if not interested in doing retransmissions, and initialize opts->retransmit_id as 0.

Usage example:

struct mg_mqtt_opts pub_opts = {.topic = mg_str("mytopic"),
                                .message = mg_str("hello"),
                                .qos = 1,
                                .retain = false};
mg_mqtt_pub(c, &pub_opts);

mg_mqtt_sub()

void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts);

Subscribe to a topic specified as a struct msg_str. You can check if a subscription request succeeded by catching MG_EV_MQTT_CMD events and checking for reception of a PUBACK messsage and its result code inside the struct mg_mqtt_message

Reception of a message will trigger an MG_EV_MQTT_MSG event providing a struct mg_mqtt_message. Note that Mongoose does not handle broker retries for QoS 2 and duplicated messages have to be handled by the application in the event handler, if required

Parameters:

  • c - Connection to use
  • opts - pointer to subscription MQTT options, like QoS. The topic is expected at opts->topic as an mg_str

Return value: None

// Mongoose event handler
void fn(struct mg_connection *c, int ev, void *evd, void *fnd) {
  if (ev == MG_EV_MQTT_MSG) {
    struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
    MG_INFO(("%.*s\t%.*s", (int) mm->topic.len, mm->topic.buf),
             (int) mm->data.len, mm->data.buf);
  }
}

struct mg_mqtt_opts sub_opts = {.topic = mg_str("mytopic"),
                                .qos = 1};
mg_mqtt_sub(c, &sub_opts);

mg_mqtt_send_header()

void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags, uint32_t len);

Send an MQTT command header. Useful in handling QoS 2 and MQTT server implementations. The command can be one of the following:

#define MQTT_CMD_CONNECT 1
#define MQTT_CMD_CONNACK 2
#define MQTT_CMD_PUBLISH 3
#define MQTT_CMD_PUBACK 4
#define MQTT_CMD_PUBREC 5
#define MQTT_CMD_PUBREL 6
#define MQTT_CMD_PUBCOMP 7
#define MQTT_CMD_SUBSCRIBE 8
#define MQTT_CMD_SUBACK 9
#define MQTT_CMD_UNSUBSCRIBE 10
#define MQTT_CMD_UNSUBACK 11
#define MQTT_CMD_PINGREQ 12
#define MQTT_CMD_PINGRESP 13
#define MQTT_CMD_DISCONNECT 14

Parameters:

  • c - Connection to use
  • cmd - Command (see above)
  • flags - Command flags (see MQTT specs)
  • len - Size of what follows this header

Return value: None

Usage example:

// Mongoose event handler
void fn(struct mg_connection *c, int ev, void *ev_data) {
  if (ev == MG_EV_MQTT_CMD) {
    struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
    if (mm->cmd == MQTT_CMD_CONNECT) {
        uint8_t response[] = {0, 0};
        mg_mqtt_send_header(c, MQTT_CMD_CONNACK, 0, sizeof(response));  // Send acknowledgement
        mg_send(c, response, sizeof(response));
    }
  }
}

mg_mqtt_ping()

void mg_mqtt_ping(struct mg_connection *c);

Send an MQTT_CMD_PINGREQ command via mg_mqtt_send_header()

Parameters:

  • c - Connection to use

Return value: None

Usage example:

// Send periodic pings to all (MQTT over) WS connections
static void timer_fn(void *arg) {
  struct mg_mgr *mgr = (struct mg_mgr *) arg;
  for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
    if (c->is_websocket) mg_mqtt_ping(c);
  }
}

mg_mqtt_parse()

int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m);

Parse a buffer and fill an mg_mqtt_message structure if it contains a valid MQTT packet.

Parameters:

  • buf - buffer with MQTT packet to parse
  • len - buffer length
  • m - pointer to a struct mg_mqtt_message to be filled with the parsed message

Return value: MQTT_OK if message is successfully parsed, MQTT_INCOMPLETE if message isn't fully received and MQTT_MALFORMED if message has a wrong format.

Usage example:

// Iterate over all MQTT frames contained in buf, len
struct mg_mqtt_message mm;
while ((mg_mqtt_parse(buf, len, &mm)) == MQTT_OK) {
  switch (mm.cmd) {
    case MQTT_CMD_CONNACK:
      ...
  }
  buf += mm.dgram.len;
  len -= mm.dgram.len;
}

mg_mqtt_unsub()

void mg_mqtt_unsub(struct mg_connection *c, const struct mg_mqtt_opts *opts);

Remove subscription (unsubscribe) to a topic previously subscribed to using mg_mqtt_sub().

Parameters:

  • c - Connection to use
  • opts - pointer to MQTT options. The topic is expected at opts->topic as an mg_str

Return value: None

struct mg_mqtt_opts sub_opts = {.topic = mg_str("mytopic"),
                                .qos = 1};
mg_mqtt_sub(c, &sub_opts);
...
mg_mqtt_unsub(c, &sub_opts);

mg_mqtt_disconnect()

void mg_mqtt_disconnect(struct mg_connection *c, const struct mg_mqtt_opts *opts);

End an client MQTT connection

Note: This function does not destroy a connection; it just sends a disconnect request to the broker. Once the connection is terminated, an MG_EV_CLOSE event will be sent to the connection event handler

Parameters:

  • c - Connection to use
  • opts - pointer to MQTT options, can be NULL for MQTT 3.1.1 connections

Return value: None