Nell’articolo precedente è stata introdotta la classe Client del modulo paho.mqtt.client, assieme alle sue modalità di connessione, sottoscrizione e pubblicazione verso un broker MQTT.
Due aspetti fondamentali dell’implementazione Python di questo Client MQTT sono rappresentati dalle possibilità di utilizzo delle funzioni di callback e dai loop.
Cosa si intende per callback? Le callback sono delle funzioni che vengono passate come parametro di ingresso ad altre funzioni, per essere utilizzate al loro interno. Ciò permette di potere aggiungere dei comportamenti nuovi associati alla funzione di partenza, non presenti nell’originale implementazione. Un esempio molto semplice di come implementare un meccanismo di questo genere in Python potrebbe essere il seguente:
def func(callback):
callback()
def new_func():
print("callback!")
func(new_func)
La maniera in cui la classe Client è progettata ricorda una piattaforma ad eventi: ad ogni evento che si verifica, viene associata una funzione particolare che lo cattura, lo processa. Le funzioni di callback sono utilizzate, in questo contesto, per potere personalizzare le operazioni di cattura degli eventi con delle istruzioni non native alla classe. A differenza dell’esempio presentato poco fa, però, la classe Client ha definito dentro di sé una serie di callback predefinite che possiamo liberamente modificare a seconda dei nostri scopi.
Ad ogni tipo di evento corrisponde una callback: modificarne le istruzioni permetterà di ottenere un comportamento ben preciso associato alla cattura di quello specifico evento. Gli eventi previsti sono in totale 7, con le loro rispettive callback, riportati nella tabella sottostante.
Evento | Callback |
Connessione | on_connect() |
Disconnessione | on_disconnect() |
Sottoscrizione | on_subscribe() |
Annullamento sottoscrizione | on_unsubscribe() |
Pubblicazione messaggio | on_publish() |
Ricezione messaggio | on_message() |
Disponibilità log | on_log() |
L’altro aspetto cruciale della classe Client è l’utilizzo dei loop per la gestione del traffico dati. Quando viene chiamata una funzione di loop, il Client inizia a processare eventi di rete ad intervalli regolari; questi eventi includono l’inoltro di messaggi pubblicati, la sottoscrizione ad un topic, la ricezione di messaggi in arrivo, ecc.; queste funzioni costituiscono lo scheletro su cui si fonda il funzionamento della classe Client.
I due tipi di loop da prendere in considerazione sono:
- loop_forever(), che blocca il thread in cui viene eseguito;
- loop_start()/loop_stop(), che inizializza un thread dedicato per la gestione del traffico di messaggi MQTT.
Un esempio di codice che sfrutta questi concetti è fornito qui di seguito, come semplice implementazione di un client che ci avvisa con delle stampe a video ogni qual volta si effettua la connessione al broker (attivo sulla stessa macchina su cui eseguiamo questo codice) o si riceve un messaggio sul topic test, stampandone il contenuto:
from paho.mqtt.client import Client
client = Client(client_id = "Subscriber_test")
def on_connect(client, userdata, flags, rc):
print("Connesso con successo")
def on_message(client, userdata, message):
print( message.payload.decode() )
client.on_connect = on_connect
client.on_message = on_message
client.connect("localhost")
client.subscribe("test")
client.loop_forever()
N.B.
message.payload
è un oggetto di tipo bytes,
decode()
lo rende una stringa.
Da questo estratto si nota come le funzioni di callback vengono definite come nuove funzioni che vanno poi a sovrascrivere le versioni native dell’oggetto client, tramite le operazioni di assegnamento nelle righe 10 e 11. I parametri in ingresso alle funzioni rappresentano dati del client che possono tornare utili, in questo caso si è utilizzata la variabile message, che contiene un attributo payload che rappresenta il contenuto del messaggio MQTT ricevuto.
Il prossimo semplice programma utilizza i concetti del primo articolo per effettuare la pubblicazione di messaggi da terminale verso il topic test:
from paho.mqtt.client import Client
client = Client("Publisher_test")
def on_publish(client, userdata, mid):
print("Messaggio pubblicato")
client.on_publish = on_publish
client.connect("localhost")
client.loop_start()
messaggio = input("Inserisci il testo da inviare al topic test")
client.publish(topic = "test", payload = messaggio)
client.loop_stop()
client.disconnect()
A questo punto basterà avviare il broker (negli articoli precedenti si è scelto di utilizzare Mosquitto, più informazioni in questo articolo) ed eseguire i due programmi per osservare il corretto scambio dei messaggi tra i due client.
Quel momento in cui trovi un tutorial fatto bene in italiano 🤤🤤🤤
Thanksss 🍀
Davvero un’ottima guida!!!… Mi servirebbe un consiglio su come poter associare a due variabili i messaggi pubblicati su due Topic.
Ciao Matteo, sono felice che l’articolo ti sia piaciuto e che ti abbia potuto aiutare nei tuoi progetti!
Se intendi che vuoi tenere traccia degli ultimi messaggi ricevuti da specifici topic, puoi usare una callback come spiego in questo articolo, in cui ogni volta che ricevi un messaggio MQTT, inserisci il suo payload al’interno di un dizionario python.
Ti allego un esempio semplice che può servirti come spunto, modificandolo e smanettandoci un po’!
https://gist.github.com/Abathargh/8c3a91173d9e16b1bc1f65bd158898ba
Ottimo! Complimenti chiarissimo!
Grazie per il tutorial, mi sei stato veramente utile
Ottimo Tutorial, tutto molto chiaro…complimenti!