-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This example demonstrates how to keep track of the connection status of each individual device.
The approach is to use a topic per device, in this case it is device/id/status, and to use a retained message to indicate the last-known status.
When the device connects successfully it posts a retained message, in this case the message is “CONNECTED”
If the device initiates a disconnection then it posts a new retained message to the same topic, in this case the message is “DISCONNECTED”
The final situation to consider is when a device loses its connection. In this case, the MQTT Last Will and Testament feature is used which means the MQTT server will automatically post a message when it detects that a device has lost its connection. In this case we post a retained message of “LOST CONNECTION” to the status topic.
The applications were developed using Eclipse CDT Kepler SR1 on an Ubuntu 13.10 virtual machine running in Oracle VirtualBox.
They were tested using an instance of MessageSight for Developers 1.1, also running in VirtualBox.
You will need to have installed the Eclipse Paho C client to be able to build and run the applications.
With the level of gcc used to build these applications (4.8.1) it was necessary to have a change made to the Paho Makefile so if you have a problem building the Paho client you should try cloning the latest repository from ssh://git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.c.git and see if that fixes the problem.
There are two applications included in this repository:
- DeviceSimulator
- StatusMonitor
They are both written in C, as separate Eclipse projects under C/Eclipse in the main repository.
This application simulates a device that publishes its connection status to a topic. The application takes two arguments:
- A unique device id
- The URL of the MQTT endpoint to connect to
The main function does the following:
- checks for the correct number of arguments
- calls
connectToMQTTto establish the connection to the MQTT server - calls
getlineto wait for a line of input from the user - if the line of input is the character ‘d’ then
disconnectFromMQTTis called, otherwise the application just exits, which will trigger the server to publish the LWT message
The connectToMQTT function does the following:
- calls
initializeGlobalswhich sets up some global variables that share state between functions - creates an instance of
MQTTClient, which is the synchronous MQTT client, using the clientId of Device_id where id is the value that was passed in as the first argument to the application - calls
MQTTClient_setCallbackswhich puts the client into multi-threaded mode which allows the main thread to block later waiting for user input - calls
addWillOptionsto add the connect options relevant to the Last Will and Testament (LWT), which in this case means publishing a retained message to the status topic for the device id - connects to the MQTT server with the connect options, including the LWT configuration
- calls
publishConnectedMessageto publish a message “CONNECTED” to the status topic
The disconnnectFromMQTT function does the following:
- checks to see if the global variable containing the MQTT client handle has a non-NULL value
- if it does have a non-NULL value it checks to see if the client is connected
- if the client is connected then it calls
publishDisconnectedMessageto publish a retained message of “DISCONNECTED” to the status topic and then disconnects from the MQTT server and destroys the MQTT client
The publishConnectedMessage and publishDisconnectedMessage functions both call MQTTClient_waitForCompletion to block the calling thread until the message has been published.
The other feature worth noting is that the connecting to MQTT and publishing the status message is all driven by a single function, connectToMQTT, and that same function is called by the connectionLost function which is registered as a callback with the MQTT client so if the connection to the MQTT server is lost, the MQTT client will call connectionLost which will call connectToMQTT again which will attempt to reestablish the connection, and if it does will publish another “CONNECTED” status message.
This application monitors device status. It supports two different modes:
- It can monitor a single device
- It can monitor all devices
The main differences between the StatusMonitor application and the DeviceEmulator application are that:
- the StatusMonitor creates a subscription to either a topic that is specific to a particular device or a wildcard topic, depending on the mode in which the application is run
- the
messageArrivedcallback prints out the details of the received message
It is possible to run multiple instances of the StatusMonitor application, which illustrates a couple of important aspects of the publish-subscribe approach:
- A single published message can be delivered to multiple subscribers, potentially with different subscriptions
- A message publisher has no knowledge of which subscribers, if any, are getting messages and additional subscribers can be added after a publisher is deployed without any affect on the publisher.
In this mode the application takes two arguments:
- the device id to monitor
- the URL of the MQTT endpoint to connect to
The topic that is subscribed to is device/1/status if the id supplied is 1 for example.
In this mode the application takes only one argument: the URL of the MQTT endpoint to connect to.
The topic that is subscribed to in this case is device/+/status which subscribes the status topic of every device in a single subscription.
To test the applications, run two instances of the StatusMonitor application, one with a device id and one without, followed by two instances of the DeviceSimulator application, each with a unique device id.
If you want to run the StatusMonitor application outside of Eclipse you can find the executable at C/Eclipse/StatusMonitor/Debug/StatusMonitor, assuming you built the Debug configuration, and similarly for the DeviceSimulator application.
When you start the StatusMonitor you should see the message Have connected and subscribed. Press <Enter> to terminate.
When you start the DeviceSimulator you should see the message Have connected. Input d then <Enter> to disconnect, anything else then <Enter> to terminate
If you have previously run the DeviceSimulator you should see the most recent status message for each device in the instance of the StatusMonitor without a device id. For example, the last time I ran the StatusMonitor using the command ./StatusMonitor tcp://192.168.56.4:1883 I saw:
message arrived on topic device/1/status: DISCONNECTED
message arrived on topic device/123456789/status: DISCONNECTED
so I can see that previously devices with ids 1 and 123456789 had connected and both had disconnected cleanly.
In the instance of the StatusMonitor with a device id you should see the most recent status message for just that one device, for example the last time I ran the StatusMonitor for device 1 using the command ./StatusMonitor 1 tcp://192.168.56.4:1883 I saw message arrived on topic device/1/status: DISCONNECTED and you may see this before the message saying the StatusMonitor has connected.
Once the instances of the StatusMonitor have connected, start an instance of the DeviceSimulator with the same device id that you used with the instance of the StatusMonitor that is specific to the device. In my case I ran an instance of the DeviceSimulator with an id of 1 with the command ./DeviceSimulator 1 tcp://192.168.56.4:1883. You should see the following message in both StatusMonitor instances: message arrived on topic device/1/status: CONNECTED
Start another instance of the DeviceSimulator with a different id, in my case I chose 2 so I ran ./DeviceSimulator 2 tcp://192.168.56.4:1883. You should not see anything from the instance of the StatusMonitor for id 1 but in the other instance of StatusMonitor that is monitoring the status of all devices you should see: message arrived on topic device/2/status: CONNECTED
If you disconnect device 1 cleanly by typing d and then the Enter key in the instance of the DeviceSimulator for id 1 you should see the following message printed out by both instances of the StatusMonitor: message arrived on topic device/1/status: DISCONNECTED
If you just press the Enter key in the instance of the DeviceSimulator for id 2 you should see the following message from the instance of the StatusMonitor that is monitoring the status of all devices: message arrived on topic device/2/status: LOST CONNECTION which is the Last Will and Testament message that the DeviceSimulator registered when it established the MQTT connection.
If you stop each of the StatusMonitor instances by pressing the Enter key and then start the instance that monitors all devices again you should see the appropriate message printed for each device, showing that the MQTT broker has stored these messages as they are retained messages.