This document describes the implementation of the MQTT-SN demo service running on nRF52-DK boards. This should also provide information on how to modify and extend it for own purposes.
This part of the demo uses MQTT-SN client running over the embeNET wireless communication protocol. The MQTT-SN protocol is a version of the popular Message Queuing Telemetry Transport (MQTT) protocol but made suitable for Sensor Networks that utilize UDP transport protocol instead of TCP. This implementation is based on the MQTT-SN specification version 1.2.
This client supports the following functions:
More information about the client is available here.
The service is implemented as a C module called mqttsn_client_service.c. The API of the service consists of 4 functions:
The service is mostly event driven and uses a single embeNET Node task implemented by the mqttsnServiceTask function, which goes through a series of states, described by mqttsnServiceState enumeration.
The MQTT-SN demo service initialzes the MQTT-SN client and tries to connect to the gateway, which is assumed to run on the border router. Once connected it registers two topics:
where UID is the nodes UID expressed in hex format. The service also subscribes to a topic:
When the service is running, every 10 seconds a message is published on the uptime/UID topic, which includes node's uptime in seconds in a simple JSON format. If a user presses a button on the board, a message is published on the button/UID topic, including button press counter in a simple JSON format. Such message is sent upmost once every second.
When a message is published on the ledcontrol topic the service tries to match it to one of the following commands: led1on, led1off, led2on, led2off, led3on, led3off to change the state of 3 LEDs present on the board.
If the service notices that it is disconnected from the gateway, it will try to reconnect automatically.
Similar to MQTT, the MQTT-SN protocol defines several Quality of Service (QoS) levels. The current implementation of the MQTT-SN client uses only QoS 0. This means that the message delivery is best-effort only and is not guaranteed. This also means that the client may not be able to detect when it gets disconnected from the gateway.
We will explain the service operation showing the typical flow of events.
The mqttsn_client_service_init does two things: initializes the client and creates a service task.
But first a MQTT-SN clientId is constructed as a string "ClientUID" where UID is the nodes UID expressed in hex.
Similarly, uptime/UID and button/UID topics are constructed:
Next the MQTT-SN client is initialized:
This initializes the client, listening on port number 1885.
The mqttEventHandlers structure groups several MQTT-SN related event handlers:
Next the embeNET Node task is created:
When the node joins the network, the service is started through a call to mqttsn_client_service_start. This simply sets up initial state of the state machine and schedules the service task to run immediatelly.
Initially, the service task mqttsnServiceTask is in the CONNECTING state. in thas state, the border router address is gathered.
Next we perform a clean connect
If successful, the onMQTTConnected will be called. However, this will not happen if the gateway is not responding. For such case we plan the task to try again afer 10 seconds.
If the client connects to the gateway, the onMQTTConnected callback is called. From within this callback we move to the next state and reschedule the task to run immediatelly.
We are now in the REGISTER_UPTIME_TOPIC state and the mqttsnServiceTask runs again. Here we register the uptime/UID topic in the gateway:
When the topic is registered, the provided onMQTTTopicRegistered will be called.
From within this callback we switch the state to REGISTER_BUTTON_STATE_TOPIC:
and reschedule the service task:
The same thing happens with the button/UID topic and we finally land in the SUBSCRIBE_TO_TOPIC state.
We are now in the SUBSCRIBE_TO_TOPIC state and the mqttsnServiceTask runs again. Here we subscribe to the ledcontrol topic:
and move to normal operation state RUNNING:
Note, that when subscribing to topic we provided a callback function onLedcontrolUpdate. This function will be called when a message is published on the ledcontrol topic. Within that function we will check if the received string is a predefined command and act accordingly.
We are now in the RUNNING state and the mqttsnServiceTask runs again. We get the local time:
And construct a simple JSON:
We next publish it on the uptime/UID topic:
and reschedule this activity in 10s:
This is done from within the mqttsn_client_service_proc function that is called periodically. The function checks for button press. Once detected we prepare a simple JSON message:
and next we publish it:
The rest of the code is used to limit the number of messages to one per second at most.
When the MQTT-SN client notices that the gateway disconnected it, it will call the provided onMQTTDisconnected calback.
Within that callback we cancel the service task.
Next we re-initalize the client:
and restart the task again
When the node leaves the network, the mqttsn_client_service_stop function is called and the MQTT-SN demo service is stopped. Here we just cancel the task and re-initalize the client:
The service will be started again once the node joins the network once more.