# Seminario 4: IoT: LoRaWAN & MQTT
###### tags: `SEMINARIO`
# Block 1: MQTT using a web client
For the experiment you will use an MQTT client that can be used in any OS, it's called MQTT-explorer:

You have to install it from here: http://mqtt-explorer.com
## Connecting to a public broker
There are various public MQTT brokers, for example:
* broker.hivemq.com
* broker.mqttdashboard.com
* test.mosquitto.org
In this session we will use the one offered by HiveMQ (broker.hivemq.com). Fill in the data as indicated below:

Then click on ```ADVANCED```, and add a topic:

if you want you can assing your own client ID. Now click on ```BACK```, and then on ```CONNECT```. You will start seeing something like this:

## Some basic exercises
Let's start with an easy one. Click on the ```DISCONNECT``` button. Now add a subscription to the topic ``Spain/Valencia/UPV``, then CONNECT once again.
Now, (1) write the same **identical** text for the topic (i.e., ``Spain/Valencia/UPV``) **in the ``topic`` field of the Publish section**, select the ```raw``` option and write a text in the box below. **The text can be whatever you want** (e.g., ``Ciao!!``). When you are done click on the ``Publish`` button.
You'll get something like the image below... **plus all the messages written by all the other clients.** With just one publish action you actually reached various devices!!

:::warning
Quick tests:
1. What happen if you write ``spain/valencia/upv`` instead?
2. How would you build a messaging app?
:::
### Simple data collection using MQTT
Let's use now MQTT Explore with the following parameters:
```
Broker: eu1.cloud.thethings.network:1883
Username: lopys2ttn@ttn
Password: NNSXS.A55Z2P4YCHH2RQ7ONQVXFCX2IPMPJQLXAPKQSWQ.A5AB4GALMW623GZMJEWNIVRQSMRMZF4CHDBTTEQYRAOFKBH35G2A
Topic: v3/+/devices/#
```

You will start seeing something like this:

We are currently reading two LoRaWAN sensors that are periodically sending their data to TTN from a remote lab... in Valencia.

# Block 2: Getting started with IoT devices
There are many IoT devices available in the market. I have various [LoPy4](https://pycom.io/product/lopy4/) with a [PySense](https://pycom.io/product/pysense/) board or [PyTrack](https://pycom.io/product/pytrack-2-0-x/) board, for possible projects.


LoPys are based on [MicroPython](https://micropython.org/). MicroPython is a full Python compiler and runtime that runs on the bare-metal. You get an interactive prompt, called the REPL ("Read Evaluate Print Loop"), to execute commands immediately, along with the ability to run and import scripts from the built-in filesystem. The REPL has history, tab completion, auto-indent and paste mode.
More infos can be found here: https://docs.pycom.io/gettingstarted/
A very basic tool to connect to the LoPy's REPL is a Python tool called **[mpy-repl-tool](https://mpy-repl-tool.readthedocs.io/en/latest/)**.

other, more friendly tools are available like [Atom](https://atom.io) or Microsoft’s [Visual Studio Code](https://code.visualstudio.com). Instructions are available here: https://docs.pycom.io/gettingstarted/software/
An example with Atom:

### Example: accessing the sensors of the Pysense board
The PySense offers various embedded sensors, namely:
* Ambient light sensor
* Barometric pressure sensor
* Temperature sensor
* Humidity sensor
* 3 axis 12-bit accelerometer
Take a look at the code below:
```python=
from pysense import Pysense
from LIS2HH12 import LIS2HH12 # 3-Axis Accelerometer
from SI7006A20 import SI7006A20 # Humidity and Temperature Sensor
from LTR329ALS01 import LTR329ALS01 # Digital Ambient Light Sensor
from raw2lux import raw2Lux # ... additional library for the light sensor
from MPL3115A2 import MPL3115A2,ALTITUDE,PRESSURE # Barometric Pressure Sensor with Altimeter
py = Pysense()
# Digital Ambient Light Sensor
lite_s = LTR329ALS01(py)
print("Light raw (channel Blue lux, channel Red lux): " + str(lite_s.light()))
print("Light (raw2lux): " + str(raw2Lux(lite_s.light())))
# Barometric Pressure Sensor with Altimeter
bara_s = MPL3115A2(py,mode=ALTITUDE) # Returns height in meters.
barp_s = MPL3115A2(py,mode=PRESSURE) # Returns pressure in Pascals.
print("MPL3115A2 temperature: " + str(bara_s.temperature()))
print("Altitude: " + str(bara_s.altitude()))
print("Pressure: " + str(barp_s.pressure()))
# Humidity and Temperature Sensor
temp_s = SI7006A20(py)
print("Temperature: " + str(temp_s.temperature())+ " deg C and Relative Humidity: " + str(temp_s.humidity()) + " %RH")
print("Dew point: "+ str(temp_s.dew_point()) + " deg C")
# 3-Axis Accelerometer
acel_s = LIS2HH12(py)
print("Acceleration: " + str(acel_s.acceleration()))
print("Roll: " + str(acel_s.roll()))
print("Pitch: " + str(acel_s.pitch()))
# ... and also..
print("Battery voltage: " + str(py.read_battery_voltage()))
```
You'll get something like:

A standard MicroPython project will have a **lib** folder for additional libraries, and two Python files: **main.py** and **boot.py**.
- `lib` folder: For example, the extra sensor libraries for the Pytrack, Pysense and Pyscan are put in this folder.
- `main.py` This script runs directly after boot.py and should contain the main code you wish to run on your device.
- `boot.py` This is the first script that runs on your module when it turns on. This is often used to connect a module to a network without cluttering up the main.py file.
# Block 3: LoRaWAN
In this block we will review the process required to send sensor data using LoRaWAN , that is moving data from the sensor to the Network Server (NS). As network server we use [**The Things Networks**](https://www.thethingsnetwork.org). Another big Network Server is [Loriot.](https://www.loriot.io/community-server.html)
A lot of useful information is available [here](https://www.thethingsnetwork.org/docs/).
The following provides some examples on how to use the TTN NS.
## Register with The Things Network
To start using TTn you need to create an account here: https://account.thethingsnetwork.org/register
Then, you will mmanage your applications and devices via [The Things Network Console](https://eu1.cloud.thethings.network/console/).

### The "GATEWAYS" section

and this is the main gateway

### The "APPLICATIONS" section

For example:

### Registering a Device
The Things Network supports the two LoRaWAN mechanisms to register devices: Over The Air Activation (OTAA) and Activation By Personalization (ABP).
Basically, select "End devices" and then click on:

Detailed instructions can be found here:
https://www.thethingsindustries.com/docs/devices/adding-devices/
## Send the data
In this step we will use the device (the LoPy plus the PySense) registered in the step before to periodically send the sensed temperature, humidity and luminosity (lux).
```python=
import binascii
import machine
import micropython
import pycom
import socket
import struct
import sys
import time
from network import LoRa
from pysense import Pysense
from SI7006A20 import SI7006A20 # Humidity and Temperature Sensor
from LTR329ALS01 import LTR329ALS01 # Digital Ambient Light Sensor
from raw2lux import raw2Lux # ... additional library for the light sensor
RED = 0xFF0000
YELLOW = 0xFFFF33
GREEN = 0x007F00
OFF = 0x000000
def flash_led_to(color=GREEN, t1=1):
pycom.rgbled(color)
time.sleep(t1)
pycom.rgbled(OFF)
THE_APP_EUI = '70B3......02AE7C'
THE_APP_KEY = '1F438669F5......D2FC6501C90F0586'
def join_lora(force_join = False):
'''Joining The Things Network '''
print('Joining TTN')
# restore previous state
if not force_join:
lora.nvram_restore()
if not lora.has_joined() or force_join == True:
# create an OTA authentication params
app_eui = binascii.unhexlify(THE_APP_EUI.replace(' ','')) # these settings can be found from TTN
app_key = binascii.unhexlify(THE_APP_KEY.replace(' ','')) # these settings can be found from TTN
# join a network using OTAA if not previously done
lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)
# wait until the module has joined the network
while not lora.has_joined():
time.sleep(2.5)
# saving the state
lora.nvram_save()
# returning whether the join was successful
if lora.has_joined():
flash_led_to(GREEN)
print('LoRa Joined')
return True
else:
flash_led_to(RED)
print('LoRa Not Joined')
return False
else:
return True
pycom.heartbeat(False) # Disable the heartbeat LED
# Let's see if you inserted the required data
if THE_APP_EUI == 'VOID':
print("You must set the values of your app and device first!!")
sys.exit()
# Getting the LoRa MAC
lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
print("Device LoRa MAC:", binascii.hexlify(lora.mac()))
flash_led_to(YELLOW)
# joining TTN
join_lora(True)
py = Pysense()
tempHum = SI7006A20(py)
ambientLight = LTR329ALS01(py)
while True:
# create a LoRa socket
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0)
s.setblocking(True)
temperature = tempHum.temperature()
humidity = tempHum.humidity()
luxval = raw2Lux(ambientLight.light())
print("Read sensors: temp. {} hum. {} lux: {}".format(temperature, humidity, luxval))
payload = struct.pack(">fff", temperature, humidity, luxval)
s.send(payload)
flash_led_to(GREEN)
time.sleep(60)
```
Now, if we go in the "Live dta" section of the TTN Application, we will see something like this:

That is the data coming from the three devices that are using this application. If you click on any of the lines of the data, you'll get:

where you can find a lot of information regarding the sending of you LoRa message.
If you check the **Payload** field, you will see a sequence of bytes... and that is actually what we sent ...
To see what we actually sent, check again the file above:
```shell=python=
temperature = tempHum.temp()
humidity = tempHum.humidity()
luxval = raw2Lux(ambientLight.lux())
payload = struct.pack(">fff", temperature, humidity, luxval)
s.send(payload)
```
As you can see we are sending the values of temperature, humidity and luminosity (lux) "compressed" as a sequence of 4*3= 12 bytes (:arrow_right: ``... = struct.pack(">fff",...``).
Now, to allow TTN to interpret these sequence of bytes we have to go the the section **Payload Format** and insert some specific code to interpret the input bytes.
