No description
Find a file
2018-07-30 03:46:39 +02:00
.vscode General cleanup 2018-07-29 03:41:55 +02:00
doc Initial commit 2018-07-27 02:25:06 +02:00
platform Extend platform for hostname resolution functionality 2018-07-29 03:42:35 +02:00
src Add readme and fix documentation 2018-07-30 03:45:32 +02:00
tests Increase coverage by subscribing to more than one topic and unsubscribing afterwards. 2018-07-30 03:14:24 +02:00
.gitignore General cleanup 2018-07-29 03:41:55 +02:00
Makefile.linux Implement statemachine, QoS untested for now 2018-07-30 02:53:18 +02:00
Readme.md Fix readme 2018-07-30 03:46:39 +02:00

MQTT library for multiple platforms including embedded targets.

Goals for this library

  1. Readable code, modern C
  2. Simple and fool-proof API
  3. High test coverage (aim is >85% of all lines tested)
  4. Suitable for embedded or Unixy targets (no static allocation though)

Current state

  • MQTT connection as a client is working
  • All packet types are implemented
  • Supports MQTT 3.1.1 (aka. protocol level 4)
  • Platform support for linux is working
  • Test have a coverage of about 87% (lines) and 94% (functions), there is room for improvement when QoS Testing is implemented

TODO

  • [] QoS testing, client -> server QoS partly works, server -> client does not
  • [] Running in MQTT Broker mode
  • [] Last will is implemented but not exposed in API
  • [] Implement Protocol level 3 (low prio)
  • [] Implement Draft Protocol level 5 (somewhat low prio as it's a draft spec)

How to use

Building under Linux

  1. Checkout the repo
  2. Run make:
make -f Makefile.linux
  1. Grab libmqtt.a or libmqtt-debug.a and src/mqtt.h and add that into your project.

Testing under Linux

Requirements:

  • Local MQTT broker, simplest is mosquitto (can be run by calling mosquitto -v in a terminal for debug output)
  • Gcov and Lcov for coverage reports, be aware you'll need a git version of lcov for newer GCC versions (> 6.0.0)

Running the tests:

make -f Makefile.linux test

Building a coverage report

make -f Makefile.linux coverage

Be aware to create the coverage report the tests must run, so you'll need the MQTT broker.

API

Configuration

Create an instance of the config struct as following:

MQTTConfig config = { 0 }; // IMPORTANT: zero out the struct before usage! (this is C99 style)

config.client_id = "my_client";
config.hostname = "localhost";

The snippet above is the absolute minimum you'll need, but there's more to configure if you want:

typedef struct {
    char *hostname;  /**< Hostname to connect to, will do DNS resolution */
    uint16_t port;   /**< Port the broker listens on, set to 0 for 1883 default */

    char *client_id; /**< Client identification */

    char *username;  /**< User name, set to NULL to connect anonymously */
    char *password;  /**< Password, set to NULL to connect without password */
} MQTTConfig;

Connect to MQTT broker

MQTTHandle *mqtt_connect(MQTTConfig *config, MQTTEventHandler callback, void *callback_context, MQTTErrorHandler error_callback);
  • config: MQTT configuration
  • callback: Callback function to call on successful connect
  • callback_context: Just a void pointer that is stored and given to the callback on connection
  • error_callback: Error handler callback
  • Returns handle to mqtt connection or NULL on error

If the error handler is called with Host not found or Connection refused, the handler is in charge of freeing the handle by returning true or re-trying by changing settings and calling mqtt_reconnect() and returning false

The error handler should be defined like this:

bool error_handler(MQTTHandle *handle, MQTTErrorCode code) {

    return true; // kill the handle, return false to keep it
}

The event handler looks like this:

void event_handler(MQTTHandle *handle, void *context) {
    // The context pointer is the same as the time when you called `mqtt_connect`
}

Re-Connect to MQTT broker

MQTTStatus mqtt_reconnect(MQTTHandle *handle, MQTTEventHandler callback, void *callback_context);
  • handle: MQTT Handle from mqtt_connect
  • callback: Callback to call when reconnect was successful
  • callback_context: Pointer to give the callback
  • Returns status code

Usually called in the MQTTErrorHandler callback, if called on a working connection the connection will be disconnected before reconnecting.

If there were registered subscriptions they will be re-instated after a successful reconnect.

Subscribe to a topic

MQTTStatus mqtt_subscribe(MQTTHandle *handle, char *topic, MQTTPublishEventHandler callback);
  • handle: MQTT Handle from mqtt_connect
  • topic: Topic to subscribe
  • callback: Callback function to call when receiving something for that topic
  • Returns status code

You may use the same callback function for multiple topics. The callback function looks like this:

void publish_handler(MQTTHandle *handle, char *topic, char *payload) {
    // the payload is zero terminated by the library, so it can be used as
    // a standard c-string immediately.
}

Un-Subscribe from a topic

MQTTStatus mqtt_unsubscribe(MQTTHandle *handle, char *topic);
  • handle: MQTT Handle from mqtt_connect
  • topic: Topic to unsubscribe
  • Returns status code

Publish something to the broker

MQTTStatus mqtt_publish(MQTTHandle *handle, char *topic, char *payload, MQTTQosLevel qos_level);
  • handle: MQTT Handle from mqtt_connect
  • topic: Topic to publish to
  • payload: Message payload to publish
  • Returns status code

This uses a c-string as the payload, theoretically the protocol would allow for binary payloads, but this is currently not supported.

Disconnect from MQTT broker

MQTTStatus mqtt_disconnect(MQTTHandle *handle, MQTTEventHandler callback, void *callback_context);
  • handle: MQTT Handle from mqtt_connect
  • Returns status code

Attention: do not use the handle after calling this function, all resources will be freed, this handle is now invalid!