# An hands-on introduction to MQTT
This lab aims to offer you an hands-on experience with MQTT. You will perform experiments that will allow you to learn how to "publish" and "subscribe" to data. To this end you will use:
1. your own broker
1. a "sandbox" external broker
1. the **ThingSpeak** and **Ubidots** platform
You will learn how to:
* install and configure an MQTT broker
* interchange data using MQTT clients based on Python and MicroPython for the LoPy
* use MQTT to feed data to cloud based IoT platforms
## Hardware
> All devices in the lab must share the same WLAN.
Each group will use a computer and a LoPy connected via USB through either an extension board or a PySense board.
# Block 0: Installing the MQTT broker on your computer
For our experiments we will use [**Mosquitto**](https://mosquitto.org/), which is part of the [Eclipse Foundation](http://www.eclipse.org/) and is an [iot.eclipse.org](https://projects.eclipse.org/projects/technology.mosquitto) project. The manual page can be found here [`man page`](https://mosquitto.org/man/mosquitto-8.html).
Detailed installation indications can be found here: https://mosquitto.org/download/
As a quick guide:
* Linux distros like Debian/UBUNTU/Raspian already have Mosquitto in their repositories... so it's enough with:
```shell=bash
sudo apt-get update
sudo apt-get install mosquitto mosquitto-clients
```
* with *Ubuntu MATE* maybe you'll need to add this before:
`sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa`
* with Macs, Mosquitto can be installed from the homebrew project. See http://brew.sh/ and then use “brew install mosquitto”
### Managing the broker
#### ... with Debian/UBUNTU/Raspian
To start and stop its execution use:
```shell=bash
sudo /etc/init.d/mosquitto start/stop
```
if necessary, to avoid that it restarts automatically, do: `sudo stop mosquitto`
To run the broker execute:
```shell=bash
sudo mosquitto –v
```
> note: "-v" stands for "verbose mode" and can be useful at the beginning to see what is going on in the broker. Can be convenient to use a dedicated terminal for the broker to execute in, if the "-v" option is used.
To check if the broker is running you can use the command:
```shell=bash
sudo netstat -tanlp | grep 1883
```
> note: "-tanlp" stands for: tcp, all, numeric, listening, program
alternatively use:
```shell=bash
ps -ef | grep mosquitto
```
#### ... with Mac OS
To start and stop its execution use:
```shell=bash
/usr/local/sbin/mosquitto -v
```
> note: "-v" stands for "verbose mode" and can be useful at the beginning to see what is going on in the broker. Can be convenient to use a dedicated terminal for the broker to execute in, if the "-v" option is used.
or:
```shell=bash
/usr/local/sbin/mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf
```
or:
```shell=bash
brew services start/stop mosquitto
```
To check if the broker is running you can use the command:
```shell=bash
sudo lsof -i -n -P | grep 1883
```
or:
```shell=bash
ps -ef | grep mosquitto
```
## Clients for testing
The broker comes with a couple of useful commands to quickly publish and subscribe to some topic. Their basic syntax is the following.
```shell
mosquitto_sub -h HOSTNAME -t TOPIC
mosquitto_pub -h HOSTNAME -t TOPIC -m MSG
```
More information can be found:
* https://mosquitto.org/man/mosquitto_sub-1.html
* https://mosquitto.org/man/mosquitto_pub-1.html
---
---
# Block 1: some basic example.
## Set-up
Open three terminals (e.g., `xterm`) in your computer, more or less like this:
![](https://i.imgur.com/KOcNjwz.jpg=400x400)
The biggest terminal on the right will be used to see the execution of the broker, the two smaller terminals will be used to execute the publisher and the subscriber, respectively.
Now, run the broker with the `-v` flag in the biggest terminal.
## Exercises
Let's start with a easy one. In one of the small terminals write:
```shell
mosquitto_sub -t i/LOVE/Python
```
the broker terminal should show something like:
![](https://i.imgur.com/5nMOywi.png)
the broker registered the subscription request of the new client. Now in the other small terminal, execute:
```shell
mosquitto_pub -t i/LOVE/Python -m "Very well."
```
in the broker terminal, after the new registration messages, you'll also see something like:
![](https://i.imgur.com/s7zROiH.png)
meaning that the broker received the published message and that it forwarded it to the subscribed client. In the terminal where `mosquitto_sub` is executing you'll see the actual message appear.
Try now:
```shell
mosquitto_pub -t i/love/python -m "Not so well"
```
**What happened? Are topics case-sensitive?**
Another useful option of `mosquitto_pub` is `-l`. Execute the following command:
```shell
mosquitto_pub -t i/LOVE/Python -l
```
and start typing some line of text. It sends messages read from stdin, splitting separate lines into separate messages. Note that blank lines won't be sent. You basically obtained a MQTT based **"unidirectional chat"** channel...
### ... about Keepalive
By the way, if you kept the broker running with the `-v` option until now in a separate window, you can see various lines like:
```
1524673958: Sending PINGRESP to mosqpub|3592-iMac-de-Pi
1524673985: Received PINGREQ from mosqsub|3587-iMac-de-Pi
```
this simply shows that the broker and the client are interchanging these special messages to know whether they are still alive.
### QoS (Quality of Service):
Adding the `-q` option, for example to the `mosquitto_pub` you'll see the extra message that are now interchanged with the broker. For example, doing:
```shell
mosquitto_pub -t i/LOVE/Python -q 2 -m testing
```
you'll get:
![](https://i.imgur.com/wLqMrev.png)
compare this sequence of messages with the one obtained with `-q 0` or with `-q 1`.
### Retained messages:
Normally if a publisher publishes a message to a topic, and *no one is subscribed* to that topic the message is simply discarded by the broker. If you want your broker to remember the last published message, you'll have to use the ```retain``` option. Only one message is retained per topic. The next message published on that topic replaces the retained message for that topic.
> To set the retain message flag you have to add `-r` using the Mosquitto clients.
So try the following cases, but **remember now to always execute, for each test, the subscriber after** the publisher:
1. Publish a message with the retain message flag not set, like we did before. What happens?
1. Publish a message with the retain message flag set (`-r`). What happens?
1. Publish several (different) messages with the retain message flag set before starting the subscriber. What happens?
2. Publish a message with the retain message flag **not** set again. What happens?
Finally, how do I remove or delete a retained message? You have to publish a blank message(`-m ""`) with the retain flag set to true which clears the retained message. Try it.
### Public brokers
There are also various public brokers in Internet, also called `sandboxes`. For example:
* `test.mosquitto.org`
* more infos at: http://test.mosquitto.org/
* `iot.eclipse.org`
* more infos at: https://iot.eclipse.org/getting-started#sandboxes
* `broker.hivemq.com`
* more infos at: http://www.hivemq.com/try-out/
* http://www.mqtt-dashboard.com/
we will always access them through port `1883`.
**Repeat some of the exercise above with one of these sandboxes (remember to use the `-h` option). Any difference?**
# Block 2: MQTT clients with MicroPython and the LoPy
> **All the code that you will be using is available here https://github.com/pmanzoni/MQTT_handson_code**
## First, some basic code
### The `ufun.py` library
To ease the programming of the following exercises some generic code is provided in a library called ```ufun.py``` available in the repository indicated above. The library provides the code to:
* `connect_to_wifi()`: connects the LoPy to a WiFi LAN. By properly passing the values `wifi_ssid` and `wifi_passwd` this function will try three times to connect to the specified AP, exiting if the operation is not possible.
* `random_in_range()`: generates random numbers in a range, and
* `set_led_to()` and `flash_led_to()`: simplify the control of the LED.
_Take a quick look at the code to understand how it works._
### Installing the MQTT client library in the LoPy
The LoPy devices require a MQTT library to write the client application. The code is available in the [above described repository.](#Block-2-MQTT-clients-with-MicroPython-and-the-LoPy) You basically need to download the **`mqtt.py`** file and copy it in the directory of your project.
## Let's start: a simple subscriber
The code below represent a simple subscriber. As a first step it connects to the WiFi network available in the lab.
> **Remember to properly assign a value to variables: `wifi_ssid`, `wifi_passwd`, and to personalize the value of `dev_id`.** `dev_id` allows to identify your specific device
> In this case we use the broker `test.mosquitto.org` but you can use any other accessible broker.
```python=
# file: a_simple_sub.py
from mqtt import MQTTClient
import time
import sys
import pycom
import ufun
wifi_ssid = 'LOCAL_AP'
wifi_passwd = ''
dev_id = 'PMtest'
broker_addr = 'test.mosquitto.org'
def settimeout(duration):
pass
def on_message(topic, msg):
print("Received msg: ", str(msg), "with topic: ", str(topic))
### if __name__ == "__main__":
ufun.connect_to_wifi(wifi_ssid, wifi_passwd)
client = MQTTClient(dev_id, broker_addr, 1883)
client.set_callback(on_message)
print ("Connecting to broker: " + broker_addr)
try:
client.connect()
except OSError:
print ("Cannot connect to broker: " + broker_addr)
sys.exit()
print ("Connected to broker: " + broker_addr)
client.subscribe('lopy/lights')
print('Waiting messages...')
while 1:
client.check_msg()
```
**Now, in a terminal and using `mosquitto_pub`, write the proper command to send some message to the LoPy.**
## A simple publisher
Let's produce some random data using the code below. As before, it first connects to the WiFi network available in the lab.
> **Remember to properly assign a value to variables: `wifi_ssid`, `wifi_passwd`, and `dev_id`.**
> In this case we use the broker `test.mosquitto.org` but you can use any other accessible broker.
```python=
# file: a_simple_pub.py
from mqtt import MQTTClient
import pycom
import sys
import time
import ufun
wifi_ssid = 'LOCAL_AP'
wifi_passwd = ''
dev_id = 'PMtest'
broker_addr = 'test.mosquitto.org'
def settimeout(duration):
pass
def get_data_from_sensor(sensor_id="RAND"):
if sensor_id == "RAND":
return ufun.random_in_range()
### if __name__ == "__main__":
ufun.connect_to_wifi(wifi_ssid, wifi_passwd)
client = MQTTClient(dev_id, broker_addr, 1883)
print ("Connecting to broker: " + broker_addr)
try:
client.connect()
except OSError:
print ("Cannot connect to broker: " + broker_addr)
sys.exit()
print ("Connected to broker: " + broker_addr)
print('Sending messages...')
while True:
# creating the data
the_data = get_data_from_sensor()
# publishing the data
client.publish(dev_id+'/sdata', str(the_data))
time.sleep(1)
```
**Now, in a terminal and using `mosquitto_sub`, write the proper command to read the generated data.**
---
# Block 3: Final exercises
Now let's work on some final exercises to put together most of what we saw in this lab session. Since you'll have to write some MQTT Python program (_not MicroPython_ :smirk:) for your computer, you have to install the [Paho library](https://www.eclipse.org/paho/clients/python/) that I described in class; it's just one step, execute:
```shell
sudo pip install paho-mqtt
```
## The first
Let's control remotely the color of the LoPy's LED using MQTT.
![block 3, first exercise](https://i.imgur.com/Y7TDE2U.png)
**Code “p1”.** This code runs in the LoPy, so you must use MicroPython, and has to:
* Connect each LoPy to its own 'private' broker; 'private' means that each user should use a different broker, basically the one you installed at the beginning of this Lab session.
* Have the LoPy to change the color of its LED according to the "instructions" it receives using MQTT. Use the functions in library `ufun.py` to control the LED.
**Code “p2”.** This code runs in a computer, so you must use Python, and has to:
* Connect to the LoPy 'private' broker.
* Publish the "instructions", using MQTT, to inform the LoPy to which color has to set its LED:
1) Try first simply using: `mosquitto_pub`
2) Then, write a program that reads 2 parameters: the broker address and the LED color you want that specific LoPy to show.
3) Finally, try to control the LoPy of another group.
## The second
Now repeat the previous exercise but using a unique ("common") broker for the whole lab. It could either be one running in a computer in the lab or a remote one (e.g., test.mosquitto.org). How will you identify a specific LoPy now?
![block 3, second exercise](https://i.imgur.com/V2q18hb.jpg)
---
# Block 4: Sending data to a cloud based platform
In this block you will experiment about how MQTT can be used to send data to a cloud based platform. This procedure allows you to store your data in a cloud based repository and to analyze your data with software tools made available by the used platform.
## Using ThingSpeak
ThingSpeak is an IoT analytics platform service that allows you to aggregate, visualize and analyze live data streams in the cloud. ThingSpeak provides instant visualizations of data posted by your devices to ThingSpeak. With the ability to execute MATLAB® code in ThingSpeak you can perform online analysis and processing of the data as it comes in.
### Creating a *channel*
You first have to sign in. Go to https://thingspeak.com/users/sign_up and create your own account. Then you can create your first channel. Like for example:
![](https://i.imgur.com/siPq11m.png =300x400)
When a channel is created it is set as _private_. Set it to **public** as indicated in the figure below:
![](https://i.imgur.com/Dforjus.png)
Now you can take a look at it, as shown in the figure below. No data is plotted for the moment.
![](https://i.imgur.com/CYPVnr4.png)
You need the data in the API Keys section to connect to your channel.
![](https://i.imgur.com/YZt82yB.png)
### Exercise
ThingSpeak offers either a REST and a MQTT API to work with channels. See here: https://es.mathworks.com/help/thingspeak/channels-and-charts-api.html
For this exercise you will need the documentation specific to **publish a message to update a single channel field** using MQTT. It is here: https://es.mathworks.com/help/thingspeak/publishtoachannelfieldfeed.html
#### First step: use `mosquitto_pub`
Use `mosquitto_pub` to send a value to your channel:
Consider that:
1. the hostname of the ThinSpeak MQTT service is "mqtt.thingspeak.com"
2. the topic you have to use is `channels/<channelID>/publish/fields/field<fieldnumber>/<apikey>` where you have to replace:
* <channelID> with the channel ID,
* <fieldnumber> with field number that you want to update, and
* <apikey> with the write API key of the channel.
3. finally, remember that ThingSpeak requires you to:
* set the PUBLISH messages to a QoS value of 0.
* set the connection RETAIN flag to 0 (False).
* set the connection CleanSession flag to 1 (True).
* Be careful!!!:
* remember to add the string 'fields'
channels/<channelID>/publish/**fields**/field<fieldnumber>/<apikey>
* `field<fieldnumber>` means, for example, **field1**
* use the **Write** API Key
#### Second step: use a Python program.
Using as a reference the code in file `paho-code/example4.py` in the GitHub repository, create a periodic publisher that sends the generated number to your ThingSpeak channel.
#### Third step: use a MicroPython program.
Using as a reference the code of the previous step, create a MicroPython periodic publisher that sends the generated number from your LoPy to your ThingSpeak channel.
## Using Ubidots
Repeat the previous exercise with the Ubidots platform. You will have to first create your free account here: https://app.ubidots.com/accounts/signup/ Then create a device:
![](https://i.imgur.com/CkHHqh3.png)
and then create a "Default" type variable:
![](https://i.imgur.com/ITZeABD.png)
Now we will send data to our device using MQTT. Take a look first to the MQTT API Reference: https://ubidots.com/docs/api/mqtt.html
#### First step: use `mosquitto_pub`
Use `mosquitto_pub` to send a value to your device:
Consider that:
1. the hostname for educational users is "things.ubidots.com". To interact with it, you will need a TOKEN. The easiest way to get yours is clicking on “API Credentials” under your profile tab:
![](https://i.imgur.com/QMXvJL0.png)
In my case I have:
![](https://i.imgur.com/72pXlm0.png)
To connect to the MQTT broker you'll have to use your Ubidots TOKEN as the MQTT username, and leave the password field empty.
2. the topic you have to use is **`/v1.6/devices/{LABEL_DEVICE}/{LABEL_VARIABLE}`** where you have to replace the fields `{LABEL_DEVICE}` (e.g., VLCtesting) and `{LABEL_VARIABLE}` (e.g., my_value).
4. The data must be represented using JSON. The simplest format is: `{"value":10}`
So, summing up, to send value 25 to variable `my_value` of device VLCtesting
```
mosquitto_pub -h things.ubidots.com -u A1E-2DvBg......TsjaOcG4SRuTkgH -P ''
-t /v1.6/devices/vlctesting/my_value -m '{"value":25}'
```
> Be careful on the use of `'`and `"` and on the actual identifiers of the device and the variable (e.g., uppercase, lowercase, ...)
![](https://i.imgur.com/EEPGJaR.png =200x200)
You'll get:
![](https://i.imgur.com/xNFjzBv.png =400x300)
So try to repeat all the previous steps with your own device and variable.
#### Second step: use a Python program.
As before, and using as a reference the code in file `paho-code/example5-prod.py` in the GitHub repository, create a periodic publisher that sends the generated number to your Ubidots device.
#### Third step: use a MicroPython program.
Using as a reference the code of the previous step, create a MicroPython periodic publisher that sends the generated number from your LoPy to your Ubidots device.