This tutorial demonstrates how Mongoose Library can be used to implement an MQTT client. We'll create an MQTT client that:
- Connects to the public HiveMQ MQTT server
- When connected, subscribes to the topic
- Publishes message
- Receives that message back from the subscribed topic and closes the connection
- Creates a timer that checks if a connection is closed, and reconnects to repeat the whole process
A full source code for this tutorial is at https://github.com/cesanta/mongoose/tree/master/examples/mqtt-client
First we declare global variables to make it easy to change tunable parameters, like MQTT server address, topic names, and QoS level.
Also, we make an MQTT connection pointer,
s_conn, globally visible.
A reconnection timer function is going to check that pointer for NULL,
and if it is NULL, a timer function would create a connection. Then,
a connection event handler sets this pointer to NULL when a connection closes.
main() function is simple: we initialise an event manager and
start the event loop, as usual. Also we create a timer - note that
a timer is created on stack but since it is declared in
main(), it lives
as long as the application is running.
Note that a timer is initialised
after the event manager gets initialised. That is important because a timer
is created with
MG_TIMER_RUN_NOW flag with executes timer function
immediately. Timer function uses event manager, so it must be initialised.
Note that the timer function is called with the interval of 3 seconds. Event manager poll timeout is 1 second. It is important to keep polling timeout less than timer interval - because timers are checked at every polling cycle, and if there are no network events, poll function sleeps for the whole duration of the polling interval. If it is larger than a timer timeout, timer invocation could be missed.
The event loop executes until termination signal is received. After that,
mg_timer_free() functions are called which perform
Timer function implements the reconnection logic and is trivial. It creates
a client connection
s_conn if it is NULL. This pattern should be used for
any type of client connection that must be kept alive.
The event handler function checks which event
ev has arrived and acts
MG_EV_OPEN event is the very first event that is sent
to every connection when it is just created and added to the event manager.
In our case, we simply log that fact:
On any error - for example, DNS lookup failure, we log that error:
When TCP connection is established with the MQTT server, we initialise TLS
if the MQTT server URL is
Note, for that to work, the application must be built with TLS enabled:
$ make MBEDTLS_DIR=/path/to/your/mbedtls/installation
By default, the HiveMQ URL is not TLS, so building with TLS is not required.
Then we catch
MG_EV_MQTT_OPEN event which is sent when MQTT server accepted
us as a client. There, we subscribe to the topic, and immediately publish
to the topic. Note that these functions do not immediately send data to the
MQTT server. As any other Mongoose output function, they just append data
to the output buffer. Data gets sent when we exit the event handler and
Mongoose performs event manager poll,
When we receive a message - and we should, we print it and signal Mongoose to terminate the connection:
And when we are getting closed, we set
s_conn to NULL. Timer function later
will kick in the reconnection: