23 febbraio 2018

tutorial: come e per cosa utilizzare mqtt via mosquitto e paho su raspberry pi


Benvenuti!
Questo tutorial vi fornirà una panoramica sul protocollo MQTT e su come e per cosa utilizzarlo su Raspberry Pi grazie ai progetti mosquitto e paho.

Nota: il presente articolo contiene una infarinatura generale ed alcuni dettagli sono stati tralasciati. Se volete approfondire, non esitate a lasciare un commento o a contattarmi sui canali social.

Prima di addentrarci, vi riporto il video di supporto a questa guida che ho pubblicato sul mio canale YouTube:


Inoltre vi segnalo che nella pagina dedicata troverete tutti i tutorial da me pubblicati.


1. l'attrezzatura minima per iniziare


Per sfruttare il protocollo MQTT occorrono:
  • un Raspberry Pi qualsiasi + una microSD + un alimentatore (da almeno 2.1A)
  • Raspbian OS Lite
  • un PC per accedere via SSH al pi e sviluppare le applicazioni
  • un router (la connessione ad Internet serve solo se si vuole esporre mosquitto sul web)

Per quanto riguarda il primo punto non occorre altro: il Raspberry Pi verrà acceduto via SSH per la configurazione generale. Sarà invece indispensabile avere un alimentatore che eroghi in uscita almeno 2.1A.
Raspbian OS Lite è probabilmente la scelta migliore poiché è un sistema leggero, consuma poche risorse ed ha la possibilità di farci installare dai repository tutto il necessario.
Il PC sarà lo strumento con cui svilupperemo le applicazioni che saranno poi eseguite sul pi.
Il router serve perché il protocollo MQTT funziona sopra lo stack TCP/IP e paho comunicherà con mosquitto via indirizzo IP assegnato al pi stesso (su cui è in esecuzione mosquitto).


2. MQTT



MQTT è un protocollo nato in IBM tra il 1998 ed il 1999 che nel 2016 è diventato standard ISO per la messaggistica leggera di tipo publish-subscribe. Si posiziona direttamente al di sopra dei protocolli TCP/IP ed è stato progettato per risolvere tutte quelle situazioni in cui può essere richiesto un basso impatto e lo scambio di dati può avvenire in presenza di banda limitata.



Ci sono almeno due figure fondamentali in un pattern publish-subscribe come quello utilizzato da MQTT: al centro di tutto c'è il broker che è il responsabile della distribuzione dei messaggi (e lo fa su diversi canali tematici), e poi ci sono i vari client che si connettono/sottoscrivono ad esso (o, per meglio dire, ad uno o più canali tematici gestiti dal broker) per pubblicare dei piccoli messaggi testuali che saranno spediti a tutti gli altri client in ascolto sugli stessi canali tematici.

MQTT è un protocollo, quindi un insieme di regole che permettono il funzionamento a livello astratto di questa architettura publish-subscribe, e da solo non serve a molto. Quindi come può essere utilizzato?
Ci sono due approcci possibili: 1) implementare il broker che gestisce tutto, ed i client capaci di sottoscrivere i topic e pubblicare i messaggi; o 2) -molto più comodo- sfruttare delle implementazioni già esistenti.


3. mosquitto e paho


E qui entrano in gioco i due progetti mosquitto e paho.



Mosquitto è una implementazione completamente open-source della parte broker del protocollo MQTT. Si tratta di un progetto che fa parte della fondazione Eclipse e che è possibile scaricare ed installare un po' ovunque.

Su Raspberry Pi, in particolare su Raspbian OS, mosquitto è presente nei repository ufficiali e, semplicemente eseguendo il comando sudo apt-get install mosquitto, sarà possibile scaricarlo con tutte le librerie necessarie al suo funzionamento. Inoltre, mosquitto verrà automaticamente configurato e, a meno di voler metter mano alle varie proprietà (cosa che non vedremo in questa sede), il broker funzionerà fin da subito senza richiedere alcuno sforzo aggiuntivo!


Paho è anch'esso un progetto facente parte della fondazione Eclipse ed è una implementazione open-source della parte client del protocollo MQTT. Paho può essere integrato in una quantità smisurata di linguaggi, tra cui anche python che è il linguaggio principe quando si parla di Raspberry Pi.

Per installare la libreria per python su Raspbian OS occorre dapprima scaricare pip tramite il comando sudo apt-get install python-pip, ed una volta completata l'installazione lanciare il comando sudo pip install paho-mqtt che procederà al download effettivo di paho.

Una volta completati questi semplici passaggi si è già pronti a sviluppare applicazioni capaci di sfruttare il protocollo MQTT per scambiare messaggi.


4. Esempi


Come mostrato direttamente nel video abbinato a questo tutorial, ho realizzato due applicazioni di esempio che mostrano il funzionamento generale di una architettura publish-subscribe.


Esempio #1

Il primo scenario è molto semplice e prevede l'esecuzione su un Raspberry Pi del broker mosquitto e di due applicazioni che sfruttano il client paho: la prima per inviare messaggi incrementali su una coda tematica, e la seconda che li recupera e li mostra a video.

Di seguito i codici sorgenti delle due app:

### Client A ###

# import
import time
import paho.mqtt.client as mqtt

# broker IP address
Broker = "192.168.1.2"

# publish topic
topic = "test/topic"

# on connect function
def on_connect(client, userdata, flags, rc) :
    print("Client che invia messaggi connesso con codice: " + str(rc))

# instantiate paho MQTT client
client = mqtt.Client()

# add on_connect function to on_connect event
client.on_connect = on_connect

# connect paho client to mosquitto broker (IP, port, timeout)
client.connect(Broker, 1883, 60)

# put client's loop in background
client.loop_start()

# send messages every 2 seconds
i = 0
while True:
    i = i + 1
    client.publish(topic, "Test: " + str(i))
    sleep(2)



### Client B ###

# import
import time
import paho.mqtt.client as mqtt

# broker IP address
Broker = "192.168.1.2"

# subscribe topic
topic = "test/topic"

# on connect function
def on_connect(client, userdata, flags, rc) :
    print("Client che riceve messaggi connesso con codice: " + str(rc))
    client.subscribe(topic)

# on message function
def on_message(client, userdata, msg) :
    print(msg.topic + " " + str(msg.payload))

# instantiate paho MQTT client
client = mqtt.Client()

# add on_connect and on_message functions to client events
client.on_connect = on_connect
client.on_message = on_message


# connect paho client to mosquitto broker (IP, port, timeout)
client.connect(Broker, 1883, 60)

# client loops forever
client.loop_forever()


Questo primo esempio è molto basilare e -volendo- abbastanza inutile, ma ci permette di capire come funzioni tutto il giro e che sia possibile far dialogare tra loro due o più software sullo stack TCP/IP in modo molto semplice grazie al protocollo MQTT. 


Esempio #2

Il secondo scenario è un po' più strutturato e sfrutta la logica di publish-subscribe per compiere una operazione più complessa. Si prevede la presenza di due Raspberry Pi (ma chiaramente può funzionare anche su un solo dispositivo o su altri dispositivi eterogenei) in modo che sul primo pi siano presenti il broker mosquitto ed una applicazione che sfrutta un client paho, mentre sul secondo pi sia presente una seconda applicazione che sfrutta anch'essa un altro client paho. La prima applicazione sul primo raspberry pi resterà in attesa dell'input digitato dall'utente, ed una volta ottenuto lo trasformerà in un comando da spedire tramite MQTT all'altra applicazione. Questi comandi permettono l'accensione di tre LED colorati (giallo, rosso e verde) controllati dal secondo Raspberry Pi via GPIO.

Di seguito i codici sorgenti delle due app:

### Client A ###

# import

import time
import curses
import paho.mqtt.client as mqtt

# setup capture keyboard
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)

# broker IP address
Broker = "192.168.1.2"

# topics
pub_topic = "test/actions"
sub_topic = "test/reactions"

# on connect function
def on_connect(client, userdata, flags, rc) :
    print("Client che invia comandi attivato con codice: " + str(rc))
    client.subscribe(sub_topic)

# on message function
def on_message(client, userdata, msg) :
    print("Risposta ottenuta: " + str(msg.payload))

# on publish function
def on_publish(mosq, obj, mid) :
    print("Comando inviato con message id: " + str(mid))

# instantiate paho MQTT client
client = mqtt.Client()

# add on_connect and on_message functions to client events
client.on_connect = on_connect
client.on_message = on_message
client.on_publish = on_publish


# connect paho client to mosquitto broker (IP, port, timeout)
client.connect(Broker, 1883, 60)

# put client's loop in background
client.loop_start()

# capture user input
try:
    while True:
        char = screen.getch()
        # quit
        if char == ord('q'):
            break
        # red
        elif char == ord('r')
            client.publish(pub_topic, "red")
        # yellow
        elif char == ord('y'):
            client.publish(pub_topic, "yellow")
        # quit
        elif char == ord('g'):
            client.publish(pub_topic, "green")

# exit
finally:
    curses.nocbreak()
    screen.keypad(0)
    curses.echo()
    curses.endwin()



### Client B ###

# import
import time
import paho.mqtt.client as mqtt
import RPi.GPIO as GPIO

# LED pins
greenPin = 23
redPin = 24
yellowPin = 25

# setup GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(greenPin, GPIO.OUT)
GPIO.setup(redPin, GPIO.OUT)
GPIO.setup(yellowPin, GPIO.OUT)

# broker IP address
Broker = "192.168.1.2"

# topics (reverse Client A topics)
pub_topic = "test/reactions"
sub_topic = "test/actions"

# activate pin
def activate(client, pin):
    client.publish(pub_topic, "Attivazione PIN: " + str(pin))
    GPIO.output(pin, GPIO.HIGH)
    sleep(3)
    client.publish(pub_topic, "Disattivazione PIN: " + str(pin))
    GPIO.output(pin, GPIO.LOW)

# on connect function
def on_connect(client, userdata, flags, rc):
    print("Client che riceve comandi attivato con codice: " + str(rc))
    client.subscribe(sub_topic)

# on message function
def on_message(client, userdata, msg):
    message = str(msg.payload)
    print("Comando ricevuto: " + message)
    if message == "red" :
        activate(client, redPin)
    elif message == "green" :
        activate(client, greenPin)
    elif message == "yellow" :
        activate(client, yellowPin)

# on publish function
def on_publish(mosq, obj, mid):
    print("Risposta inviata con message id: " + str(mid))

# instantiate paho MQTT client
client = mqtt.Client()

# add on_connect and on_message functions to client events
client.on_connect = on_connect
client.on_message = on_message
client.on_publish = on_publish


# connect paho client to mosquitto broker (IP, port, timeout)
client.connect(Broker, 1883, 60)

client loops forever
client.loop_forever()


Questo secondo esempio è anch'esso molto semplice ma mostra come, avendo a disposizione un sistema di pubblicazione e sottoscrizione di messaggi, sia possibile far comunicare in modo veloce due o più software o dispositivi (o quel che si voglia) per far eseguire determinate azioni in base ai messaggi stessi scambiati. I device comunicano sui protocolli TCP/IP, quindi possono essere sotto la stessa rete oppure anche via Internet.


5. conclusioni ed ultime note


MQTT ripone la sua forza proprio nella semplicità del protocollo stesso, e sta sempre più prendendo piede nel mondo dell'IoT per tante ragioni: 1) perché è uno standard ISO, 2) perché è completamente aperto, e 3) proprio perché funziona in situazioni in cui la banda può essere ridotta e non richiede implementazioni complesse tanto che possano essere eseguite senza problemi su dispositivi che hanno poca potenza di calcolo.
Oltre al mondo IoT, questo protocollo può essere impiegato fondamentalmente ovunque, in qualsiasi scenario che preveda la comunicazione tra più client i quali debbono reagire a comandi generati da altri client. Si possono perfino pensare software che sfruttino MQTT solo per alcune fasi del loro funzionamento: ad esempio Facebook Messenger utilizza MQTT in alcune funzionalità (come lo stato dell'utente) poiché questo protocollo consente di aumentare la velocità del software stesso, usa meno banda e consuma meno energia!

Ricapitolando:
  1. MQTT è un protocollo standard che definisce delle regole per tirar su un sistema di comunicazione "snello" su stack TCP/IP secondo il pattern publish-subscribe. Esistono due figure fondamentali in questo pattern che sono il broker ed i client. Il broker gestisce i messaggi che i client inviano o ricevono tramite l'uso di code tematiche
  2. mosquitto è una implementazione open-source di un broker MQTT e paho è una implementazione open-source di un client MQTT. Su Rasperry Pi è possibile installare con pochi passaggi sia mosquitto che paho e sviluppare (ad esempio in python) applicazioni che sfruttino MQTT per dialogare tra loro via scambio di messaggi, ed eventualmente reagire ad essi
  3. il campo principe di questo protocollo è il mondo IoT, vista la semplicità ed i vantaggi che offre, ma nulla vieta di usarlo in qualsiasi tipologia di applicazione che preveda la presenza di due o più client che debbono dialogare tra loro

Bene: come indicato ad inizio guida, alcuni aspetti sono stati lasciati in secondo piano, ma se siete interessati ad approfondirli non esitate a contattarmi nei commenti di questo tutorial o del video ad esso correlato, oppure sui canali social!

Spero che la guida vi sia stata utile. Al prossimo tutorial!

Nessun commento:

Posta un commento