.vscode | ||
doc | ||
platform | ||
src | ||
tests | ||
.gitignore | ||
Makefile.linux | ||
Readme.md |
MQTT library for multiple platforms including embedded targets.
Goals for this library
- Readable code, modern C
- Simple and fool-proof API
- High test coverage (aim is >85% of all lines tested)
- 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
- Checkout the repo
- Run make:
make -f Makefile.linux
- Grab
libmqtt.a
orlibmqtt-debug.a
andsrc/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
andLcov
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 configurationcallback
: Callback function to call on successful connectcallback_context
: Just a void pointer that is stored and given to the callback on connectionerror_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 frommqtt_connect
callback
: Callback to call when reconnect was successfulcallback_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 frommqtt_connect
topic
: Topic to subscribecallback
: 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 frommqtt_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 frommqtt_connect
topic
: Topic to publish topayload
: 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 frommqtt_connect
- Returns status code
Attention: do not use the handle after calling this function, all resources will be freed, this handle is now invalid!