Try   HackMD

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:

In this session we will use the one offered by HiveMQ (broker.hivemq.com). Fill in the data as indicated below:

MQTT client

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!!

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 with a PySense board or PyTrack board, for possible projects.

LoPys are based on MicroPython. 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.

other, more friendly tools are available like Atom or Microsoft’s Visual Studio Code. 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:

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. Another big Network Server is Loriot.

A lot of useful information is available here.
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.

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).

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:

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.