Archivio

Posts Tagged ‘iot’

Mqtt e python: esempio pratico

11 Gennaio 2019 Commenti chiusi

Dopo i primi passi su Mqtt, vediamo un esempio con un’app wx.
Creiamo un frame con all’interno un semplice widget.
Usiamo per comodità una static text, in modo da poterne cambiare il background colour ed il testo contenuto.

# monitor.py
#
# A simple wx app with mqtt client example
# Send command from another client to change the widget colour.
# ON and OFF commands are accepted.

import time
import paho.mqtt.client as paho
import wx


BROKER = "test.mosquitto.org"
PORT = 1883
TOPIC = "bancaldo/test/monitor"


class MonitorPanel(wx.Panel):
    def __init__(self, parent):
        super(MonitorPanel, self).__init__(parent=parent)
        self.text = wx.StaticText(self, size=(200, 200))


class MonitorFrame(wx.Frame):
    def __init__(self, parent, title):
        super(MonitorFrame, self).__init__(parent=parent, title=title)
        self.client = None
        self.parent = parent
        self.panel = MonitorPanel(parent=self)

        self.Bind(wx.EVT_CLOSE, self.on_quit)

        self.panel.SetBackgroundColour(wx.WHITE)
        self.SetSize((200, 200))
        self.Center()

    # Mqtt client on_message callback
    def on_message(self, client, userdata, message):
        time.sleep(1)
        com = str(message.payload.decode("utf-8"))
        print("[DEBUG] received message =", 
        	  str(message.payload.decode("utf-8")))
        if com.upper() == "ON":
            self.panel.text.SetLabel('LIGHT ON!')
            self.panel.text.SetBackgroundColour(wx.GREEN)

        elif com.upper() == "OFF":
            self.panel.text.SetLabel('LIGHT OFF!')
            self.panel.text.SetBackgroundColour(wx.WHITE)
        else:
            self.panel.text.SetLabel("Unknown command:\n"
                                     "'%s'\n Use 'ON' or 'OFF' commands only!"
                                     % com)
            self.panel.text.SetBackgroundColour(wx.RED)

    def init_client(self):
        self.client = paho.Client("Mqtt Monitor")
        self.client.on_message = self.on_message
        print("connecting %s to broker " % self.client._client_id)
        self.client.connect(BROKER, PORT)
        print("subscribing %s to topic '%s'..." % (self.client._client_id,
        	                                       TOPIC))
        self.client.subscribe(TOPIC)
        self.client.loop_start()

    def on_quit(self, event):
        self.client.loop_stop()
        self.client.disconnect()
        self.Destroy()


class MQTTApp(wx.App):
    def OnInit(self):
        monitor = MonitorFrame(parent=None, title='MQTT Monitor')
        monitor.Show()
        monitor.init_client()
        return True


if __name__ == '__main__':
    app = MQTTApp(False)
    app.MainLoop()

Ha molta importanza la callback on_message, che personalizziamo qui:

class MonitorFrame(wx.Frame):
    ...
    # Mqtt client on_message callback
    def on_message(self, client, userdata, message):
        time.sleep(1)
        com = str(message.payload.decode("utf-8"))
        print("[DEBUG] received message =", 
        	  str(message.payload.decode("utf-8")))
        if com.upper() == "ON":
            self.panel.text.SetLabel('LIGHT ON!')
            self.panel.text.SetBackgroundColour(wx.GREEN)

        elif com.upper() == "OFF":
            self.panel.text.SetLabel('LIGHT OFF!')
            self.panel.text.SetBackgroundColour(wx.WHITE)
        else:
            self.panel.text.SetLabel("Unknown command:\n"
                                     "'%s'\n Use 'ON' or 'OFF' commands only!"
                                     % com)
            self.panel.text.SetBackgroundColour(wx.RED)

In pratica preleviamo il messaggio da payload e a seconda del
suo valore, coloro il widget in modo diverso.

L’assegnazione della callback, avviene durante l’inizializzazione del client mqtt,
che avviene nel metodo init_client:

class MonitorFrame(wx.Frame):
    ...
    def init_client(self):
        self.client = paho.Client("Mqtt Monitor")
        self.client.on_message = self.on_message
        print("connecting %s to broker " % self.client._client_id)
        self.client.connect(BROKER, PORT)
        print("subscribing %s to topic '%s'..." % (self.client._client_id,
        	                                       TOPIC))
        self.client.subscribe(TOPIC)
        self.client.loop_start()
    ...

class MQTTApp(wx.App):
    def OnInit(self):
        monitor = MonitorFrame(parent=None, title='MQTT Monitor')
        monitor.Show()
        monitor.init_client() # inizializzo il client mqtt
        return True


if __name__ == '__main__':
    app = MQTTApp(False)
    app.MainLoop()

Per testarne invece il funzionamento, utilizziamo l’applicazione MQTTfx,


ma andrebbe benissimo anche una shell di python, dove poter creare un client
e dare i comandi sul topic corretto:

>>> from paho.mqtt.client import Client
>>> client = Client("Mqtt Client 1")
>>> topic = "bancaldo/test/monitor"
>>> broker = "test.mosquitto.org"
>>> client.connect(broker, port=1883)
0
>>> client.publish(topic, "ON")
<paho.mqtt.client.MQTTMessageInfo object at 0x0221C750>

>>> client.publish(topic, "OFF")
<paho.mqtt.client.MQTTMessageInfo object at 0x0222A330>

>>> client.publish(topic, "FOO")
<paho.mqtt.client.MQTTMessageInfo object at 0x0221C750>


Se controlliamo la shell dove abbiamo lanciato l’app monitor.py, troveremo i messaggi di log ricevuti
grazie alla callback on_message:

(venv) C:\tmp>python monitor.py
connecting b'Mqtt Monitor' to broker
subscribing b'Mqtt Monitor' to topic 'bancaldo/test/monitor'...
[DEBUG] received message = ON
[DEBUG] received message = OFF
[DEBUG] received message = FOO
Categorie:iot, mqtt, python, wxPython Tag: , , ,

MQTT: websockets

27 Dicembre 2018 Commenti chiusi

Cosa è un websocket

Da wikipedia:

WebSocket è una tecnologia web che fornisce canali di comunicazione full-duplex attraverso una singola connessione TCP

Dopo aver visto a grandi linee cosa sia MQTT,
vediamo come utilizzarlo con i websockets.

Lato Broker

Per utilizzare i websocket con mqtt bisogna utilizzare MQTT in versione >= 1.5.4 se si utilizzerà un server locale, oppure
un broker online che supporti la tecnologia websocket.
Anche il server di test test.mosquitto.org va benissimo.

Editare il file di configurazione mosquitto.conf ed aggiungere le seguenti righe:

listener 9001

protocol websockets

Avviare il server puntando al file di configurazione appena editato:

mosquitto.exe -v -c <path_to_mosquitto_conf>\mosquitto.conf

Dove al posto di path_to_mosquitto_conf va inserito, ovviamente, il percorso del file di configurazione.

1545916129: mosquitto version 1.5.4 starting
1545916129: Config loaded from \tmp\mosquitto\mosquitto.conf.
1545916129: Opening ipv6 listen socket on port 1883.
1545916129: Opening ipv4 listen socket on port 1883.
1545916129: Opening websockets listen socket on port 9001.

Il broker, come si nota, è in ascolto sia sulla porta 1883 (non le ho decommentate nel file conf pertanto permane attiva la
funzione principale), sia sulla 9001 per chi utilizza i websockets.

Lato Client

Per il client con python, va benissimo la solita libreria paho-mqtt.
Il procedimento è molto simile a quello di base, specificando il protocollo e settando la giusta porta di comunicazione.

>>> from paho.mqtt.client import Client
>>> c = Client("bancaldo", transport="websockets")
>>> c.connect("127.0.0.1", port=9001)
0
>>> c.loop_start()
1545916129: Opening websockets listen socket on port 9001.
1545916601: New client connected from 127.0.0.1 as bancaldo (c1, k60).
1545916601: No will message specified.
1545916601: Sending CONNACK to bancaldo (0, 0)

Abboniamo il nostro client al solito topic, creiamo un altro client, pubblichiamo un messaggio e verifichiamo che tutto funzioni.

>>> c.subscribe(topic)
(0, 1)
>>> c1 = Client("client_1", transport="websockets")
>>> c1.connect("127.0.0.1", port=9001)
0
>>> c1.loop_start()
>>> c1.publish(topic, "ON", qos=2, retain=True)
<paho.mqtt.client.MQTTMessageInfo object at 0x0268D3C0>

come si nota dal lato broker…

1545916794: Received SUBSCRIBE from bancaldo
1545916794:     home/room/lights (QoS 0)
1545916794: bancaldo 0 home/room/lights
1545916794: Sending SUBACK to bancaldo
1545916839: New client connected from 127.0.0.1 as client_1 (c1, k60).
1545916839: No will message specified.
1545916839: Sending CONNACK to client_1 (0, 0)
1545916901: Received PUBLISH from client_1 (d0, q2, r1, m1, 'home/room/lights', ... (2 bytes))
1545916901: Sending PUBREC to client_1 (Mid: 1)
1545916901: Received PUBREL from client_1 (Mid: 1)
1545916901: Sending PUBLISH to bancaldo (d0, q0, r0, m0, 'home/room/lights', ... (2 bytes))
1545916901: Sending PUBCOMP to client_1 (Mid: 1)

…tutto ok.

Categorie:iot, mqtt, python Tag: , ,

MQTT: primi passi nell’IOT

27 Dicembre 2018 Commenti chiusi

MQTT

Dal sito ufficiale “MQTT is a machine-to-machine (M2M)/”Internet of Things” connectivity protocol”.
In sostanza è un protocollo di messaggistica di tipo publish/subscribe molto leggero, progettato per la telemetria M2M (machine to machine).
MQTT sta per Message Queuing Telemetry Transport; la specifica attuale è MQTT V3.1.
I client MQTT non hanno indirizzo pertanto non sarà necessario associare ad essi, indirizzi mail ecc.
I Server, noti anche come broker, sono vari, commerciali e a scopo didattico.
Per i nostri primi passi utilizzeremo Mosquitto

Per le prime prove installeremo il broker mosquitto in locale, ma è possibile anche utilizzare il broker di test online, all’indirizzo test.mosquitto.org.

Per windows, installare gli eseguibili scaricabili qui.

Per Ubuntu (e Debian derivate):

sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
sudo apt-get update
sudo apt-get install mosquitto
sudo apt-get install mosquitto-clients

Una volta installato il broker è possibile lanciarlo in modalità “verbose”.

C:\>mosquitto -v
1545899205: mosquitto version 1.5.4 starting
1545899205: Using default config.
1545899205: Opening ipv6 listen socket on port 1883.
1545899205: Opening ipv4 listen socket on port 1883.

Come si nota il broker è in ascolto, di default, sulla porta 1883.

Cominciamo a vedere il client.
Utilizzerò python e la libreria paho-mqtt per sperimentare un po’.

Per prima cosa creare l’ambiente virtuale, da un altro prompt:

python -m venv venv

attivare l’ambiente virtuale:

venv\Scripts\activate

o su ubuntu (e debian derivate):

source venv/bin/activate

Una volta all’interno del venv installare paho-mqtt:

pip install paho-mqtt

Aprire una shell di python:

>>> from paho.mqtt.client import Client
>>> c = Client("bancaldo")
>>> c.connect("127.0.0.1", port=1883)
0

Osservando il broker, notiamo le seguenti righe:

1545899364: New connection from 127.0.0.1 on port 1883.
1545899364: New client connected from 127.0.0.1 as bancaldo (c1, k60).
1545899364: No will message specified.
1545899364: Sending CONNACK to bancaldo (0, 0)

Soffermiamoci sulla riga:

1545899364: Sending CONNACK to bancaldo (0, 0)

come da specifica:
CONNACK è un pacchetto spedito dal Server (broker) in risposta al pacchetto CONNECT che il server riceve dal Client.
Il primo pacchetto spedito dal Server deve quindi essere un pacchetto CONNACK.
Il valore 0, indica il buon esito della connessione.

1545899364: New client connected from 127.0.0.1 as bancaldo (c1, k60).

il valore k60, sta per keepalive = 60 secondi, ovvero il massimo intervallo di tempo che può trascorrere dal momento in cui il Client finisce di trasmettere un Control Packet e il momento in cui comincia a mandare quello successivo. Di default è settato a 1 minuto.
Passato questo tempo il broker manderà una richiesta di ping e si aspetterà una risposta.
se lo settassimo a 5, il PINGREQ arriverebbe al client ogni 5 sec. e questi risponderebbe.
Disconnettiamo il nostro client e riconnettiamolo settando il parametro suddetto:

>>> c.disconnect()
0
>>> c.connect("127.0.0.1", port=1883, keepalive=5)
0
1545899643: New client connected from 127.0.0.1 as bancaldo (c1, k5).
1545899643: No will message specified.
1545899643: Sending CONNACK to bancaldo (0, 0)
1545899651: Client bancaldo has exceeded timeout, disconnecting.
1545899651: Socket error on client bancaldo, disconnecting.

Cosa è successo?
Il client è stato disconnesso.
Quando un messaggio arriva al client (spedito dal broker) viene messo nel receive buffer e attende di essere letto dal client stesso. Viceversa, un messaggio spedito dal client riesiederà nel send buffer finchè non verrà spedito.
Chi si occupa di leggere i due buffer del client è una funzione built-in.
Quando trova un messaggio, in base al tipo di messaggio questa funzione chiamerà la callback di competenza.
Ad esempio in caso di messaggio CONNACK, chiamerà la callback on_connect e così via.
La funzione che fa al caso nostro in questo momento è loop_start

Ripetiamo i passaggi precedenti, attivando però il loop sul client:

>>> c.connect("127.0.0.1", port=1883, keepalive=5)
0
>>> c.loop_start()
1545901109: New client connected from 127.0.0.1 as bancaldo (c1, k5).
1545901109: No will message specified.
1545901109: Sending CONNACK to bancaldo (0, 0)
1545901114: Received PINGREQ from bancaldo
1545901114: Sending PINGRESP to bancaldo
1545901119: Received PINGREQ from bancaldo

Come si nota, il client non viene più disconnesso ed il metodo loop_start della classe Client,
si occuperà di mantenere il client connesso leggendo ciclicamente i buffer dei messaggi in entrata ed in uscita.

Il loop invocato girerà su un altro thread ed è possibile interromperlo con il metodo loop_stop.

Pubblicare messaggi

Ora proviamo a pubblicare un messaggio su un topic qualsiasi:

>>> topic = "home/room/lights"
>>> message = "ON"
>>> c.publish(topic, message)
<paho.mqtt.client.MQTTMessageInfo object at 0x023FD330>

A livello broker…

1545901738: Received PUBLISH from bancaldo (d0, q0, r0, m0, 'home/room/lights', ... (2 bytes))

Ricevere messaggi

Per ricevere i messaggi relativi ad un determinato topic, bisogna abbonarsi (subscribe) al topic stesso.
Creiamo quindi un altro client che stia in ascolto sul nostro topic:

>>> c1 = Client("client_1")
>>> c1.connect("127.0.0.1", port=1883, keepalive=60)
0
>>> c1.loop_start()
>>> c1.subscribe("home/room/lights")
(0, 1)

nel log del broker…

1545901942: New connection from 127.0.0.1 on port 1883.
1545901942: New client connected from 127.0.0.1 as client_1 (c1, k60).
1545901942: No will message specified.
1545901942: Sending CONNACK to client_1 (0, 0)
1545901997: Received SUBSCRIBE from client_1
1545902011:     home/room/lights (QoS 0)
1545902011: client_1 0 home/room/lights
1545902011: Sending SUBACK to client_1
1545902011: Sending SUBACK to client_1

come per la connessione con CONNACK, il brocker spedisce un attestato di sottoscrizione, con il messaggio SUBACK.
Il client “client_1” si è abbonato al topic, dopo che il primo client ha spedito un messaggio e, per come abbiamo stabilito le cose (vedremo più avanti come gestire la cosa), il secondo client non riceverà il messaggio.
Riceverà però tutti i seguenti, per cui rimandiamolo e vediamo che tutto funzioni:

>>> c.publish(topic, msg)
<paho.mqtt.client.MQTTMessageInfo object at 0x02580D50>
1545904123: Received PUBLISH from bancaldo (d0, q0, r0, m0, 'home/room/lights', ... (2 bytes))
1545904123: Sending PUBLISH to client_1 (d0, q0, r0, m0, 'home/room/lights', ... (2 bytes))

Come anticipato in precedenza, se vogliamo che il broker memorizzi l’ultimo messaggio del topic, in modo che questo venga spedito al client che si abbona al topic successivamente alla pubblicazione, si deve settare a True, il flag retain.

>>> c.publish(topic, "OFF", retain=True)
<paho.mqtt.client.MQTTMessageInfo object at 0x02580DB0>
1545904189: Received PUBLISH from bancaldo (d0, q0, r1, m0, 'home/room/lights', ... (2 bytes))
1545904189: Sending PUBLISH to client_1 (d0, q0, r0, m0, 'home/room/lights', ... (2 bytes))

Come si nota, “r1” indica che il flag retain è settato a True.

Abboniamo quindi un altro client, dopo la pubblicazione del messaggio…

>>> c2 = Client("client_2")
>>> c2.connect("127.0.0.1", port=1883)
0
>>> c2.loop_start()
>>> c2.subscribe(topic)
(0, 1)
1545904334: New connection from 127.0.0.1 on port 1883.
1545904334: New client connected from 127.0.0.1 as client_2 (c1, k60).
1545904334: No will message specified.
1545904334: Sending CONNACK to client_2 (0, 0)
1545904348: Received SUBSCRIBE from client_2
1545904348:     home/room/lights (QoS 0)
1545904348: client_2 0 home/room/lights
1545904348: Sending SUBACK to client_2
1545904348: Sending PUBLISH to client_2 (d0, q0, r1, m0, 'home/room/lights', ... (3 bytes))

Come si nota, l’ultimo messaggio del topic è stato spedito.

1545904348: Sending PUBLISH to client_2 (d0, q0, r1, m0, 'home/room/lights', ... (3 bytes))

Un’occhiata veloce ai valori:

d0: DUP flag -> 0 valore che deve essere settato a 0 in caso di QoS=0 (vedere specifiche MQTT)
q0: QoS -> Quality of service (vedremo più avanti)
r1: RETAIN Flag -> indica al broker se memorizzare o meno l’ultimo messaggio del topic (1=True)
m0: ID MESSAGE -> id del messaggio pubblicato in precedenza (vedi sotto)

1544437705: Received PUBLISH from bancaldo (d0, q0, r0, m0, 'home/room/light', ... (2 bytes))

Callback on_message

Sul lato client purtroppo non abbiamo molte notizie sul messaggio spedito.
Qui ci viene in aiuto la callback che viene invocata quando viene ricevuto un messaggio: on_message.
Possiamo in sostanza creare la nostra funzione ed associarla alla callback on_message;
quando verrà pubblicato un messaggio, il client che lo riceverà invocherà la callback on_message, quindi la nostra funzione:

>>> def on_message(client, userdata, message):
...     print("Topic: %s" % message.topic)
...     print("Message received:  %s" % message.payload)
...     print("Retain flag: %s" % message.retain)
...     print("Message QoS: %s" % message.qos)
...     return True
...
>>> c2.on_message = on_message

all’arrivo di un messaggio, otterremo:

>>> Topic: home/room/lights
Message received:  b'OFF'
Retain flag: 1
Message QoS: 0

Ovviamente questo vale per tutte le callbacks disponibili, che sono:

• on_disconnect: Event sulla disconnessione
• on_subscribe: Event sul Subscription ad un Topic
• on_unsubscribe: Event sul Un-subscription ad un Topic
• on_publish: Event sul Publish di un messaggio
• on_message: Event sulla ricezione di un messaggio
• on_log: Event sul Log information

QoS (Quality of Service)

MQTT fornisce 3 livelli di QOS: 0,1,2.
I livelli di QoS riguardano il tipo di connessione tra broker e client.

QoS 0: “solo una volta”

E’ il metodo più rapido e richiede solo un messaggio. Purtroppo il messaggio non è memorizzato sul mittente e non è riconoscibile. Il messaggio sarà consegnato solo una volta o non del tutto (in caso di malfunzionamenti).
Perciò non è possibile dublicare un messaggio con QoS 0.

QoS 1: “Almeno una volta”

Questo livello garantisce che il messaggio venga consegnato almeno una volta, ma potrebbe essere consegnato più di una volta. La pubblicazione con livello QOS=1 richiede 2 messaggi.
Il mittente spedisce un messaggio e attende un riconoscimento (acknowledgement: PUBACK).
Se il mittente riceve il riconoscimento (o attestato) allora notifica il client e cancella il messaggio dalla code in uscita (outbound queue). Se non riceve il riconoscimento, rispedirà il messaggio con il flag DUP settato.
Il messaggio continuerà ad essere rispedito ad intervalli regolari, finchè il mittente non riceverà un riconoscimento.
Se il messaggio sarà spedito al broker allora il broker inoltrerà tale messaggio ai subscribers, nonostante il flag “duplicate” sia stato settato.
Per questo motivo i subscribers possono ricevere il messaggio più volte.

QoS 2: “solo una volta”

Questo livello garantisce che il messaggio venga consegnato solo una volta.
Questo è il livello più lento e richiede 4 messaggi.
1 – Il mittente spedisce un messaggio e attende per un riconoscimento (PUBREC) dal broker.
2 – Chi riceve il messaggio (broker), spedisce un messaggio PUBREC.
3 – Se il mittente non riceve il riconoscimento PUBREC, rispedirà il messaggio con il flag DUP settato.
4 – Quando il mittente riceve il messaggio PUBREC, allora rilascia un messaggio PUBREL (release).
5 – Se il destinatario (broker) non riceve il messaggio PUBREL, rimanderà il messaggio PUBREC.
6 – Quando il broker riceverà il messaggio PUBREL potrà inoltrare il messaggio a tutti i subscribers.
7 – Il broker manderà un messaggio “publish complete” (PUBCOMP) .
8 – se il mittente non riceverà il messaggio PUBCOMP, rimanderà al broker il messaggio PUBREL.
8 – Quando il mittente riceverà il messaggio PUBCOMP il processo sarà completo e potrà cancellare il messaggio
dalla coda in uscita (outbound queue)

Esempio di pubblicazione con QoS=2:

>>> c.publish("home/room/lights", "OFF", qos=2, retain=True)
<paho.mqtt.client.MQTTMessageInfo object at 0x00820AB0>
1545905152: Received PUBLISH from bancaldo (d0, q2, r1, m4, 'home/room/lights', ... (3 bytes))
1545905152: Sending PUBREC to bancaldo (Mid: 4)
1545905152: Received PUBREL from bancaldo (Mid: 4)
1545905152: Sending PUBCOMP to bancaldo (Mid: 4)
1545905152: Sending PUBLISH to client_1 (d0, q0, r0, m0, 'home/room/lights', ... (3 bytes))
1545905152: Sending PUBLISH to client_2 (d0, q0, r0, m0, 'home/room/lights', ... (3 bytes))

come si nota il broker manda PUBREC al client, il client manda il PUBREL al broker, il broker manda il PUBCOMP al client e quindi viene svuotata la outbound queue spedendo il messaggio ai subscribers client_1 e client_2.

Se collegassi un client al topic:

>>> c3 = Client("Client_3")
>>> c3.connect("127.0.0.1", port=1883)
>>> c3.loop_start()
>>> c3.subscribe("home/room/lights", qos=2)
1545905329: New connection from 127.0.0.1 on port 1883.
1545905329: New client connected from 127.0.0.1 as client_3 (c1, k60).
1545905329: No will message specified.
1545905329: Sending CONNACK to client_3 (0, 0)
1545905380: Received SUBSCRIBE from client_3
1545905380:     home/room/lights (QoS 2)
1545905380: client_3 2 home/room/lights
...

e dal mittente mandassi un messaggio sul topic in QoS=2, vedrei:

c.publish("home/room/lights", "STOP", qos=2, retain=True)
1545905568: Received PUBLISH from bancaldo (d0, q2, r1, m6, 'home/room/lights', ... (4 bytes))
1545905568: Sending PUBREC to bancaldo (Mid: 6)
1545905568: Received PUBREL from bancaldo (Mid: 6)
1545905568: Sending PUBCOMP to bancaldo (Mid: 6)
1545905568: Sending PUBLISH to client_1 (d0, q0, r0, m0, 'home/room/lights', ... (4 bytes))
1545905568: Sending PUBLISH to client_2 (d0, q0, r0, m0, 'home/room/lights', ... (4 bytes))
1545905568: Sending PUBLISH to client_3 (d0, q2, r0, m2, 'home/room/lights', ... (4 bytes))

Mosquitto authentication

Le restrizioni riguardanti l’accesso ad un topic vanno settate a livello broker.
Creare un file passwords.txt (va bene qualsiasi nome) ed inserire per ogni riga una coppia
: ad es.:

client_1:pwclient1
client_2:pwclient2
client_3:pwclient3

ora bisogna effettuare l’encrypting delle password scelte e per questo si utilizza il tool fornito da mosquitto: mosquitto_passwd

C:\>mosquitto_passwd -U <percorso_password_file>

se torniamo ad aprire il file passwords.txt otteniamo:

client_1:$6$vHvY2Hm0lYnsG4C/$QXXJaQeH5aIHqjPTLWzX9GaVpHAJ+T5umRlaXeGkYY7f03flXVK6RGvIiNbYaqtlt91t6X+kO1YISeadwv+3Iw==
client_2:$6$FDuHTJgXOK2zcxkw$8799MWunGLJ3Fw2CvA4l8e+s0etpITlfYxSxe5Y1s89e4Aq2eax1dCgP9FQfVR9tISVr4DG4v7dnf02oj0NYUQ==
client_3:$6$2d6VnhZLuHO9LqoN$of+k2yqMozbUZQ1BrWlzGvuEd83DqCOHw7vnKPZaHsApmgYtNqYDANfqEWe6VQs7/KYeY1hfG7861qGN7RYp8A==

se volessi aggiungere un client con relativa password generata, direttamente da riga di comando:

C:\>mosquitto_passwd -c <percorso_password_file> <nome_client>

Attenzione che questo comando sovrascriverebbe il vecchio file delle passwords se esistente.
Per aggiungere un client ad un file esistente utilizzare il flag -b:

C:\>mosquitto_passwd -c <percorso_password_file> <nome_client> <password>

Per eliminare un client dal file delle password, utilizzare il flag -D

C:\>mosquitto_passwd -D <percorso_password_file> <nome_client>

Ora questo file di passwords va copiato nella directory di mosquitto.
Editare il file di configurazione di mosquitto mosquitto.conf per dirgli di utilizzare il nostro file

decommentare il valore allow_anonymous e settarlo a false:

allow_anonymous false

decommentare il valore password_file ed indicare il percorso del file delle password:

password_file <percorso_eseguibile_mosquitto>/<nostro_pw_file>

Lanciamo il broker indicandogli di utilizzare il file mosquitto.conf:

C:>mosquitto -v -c \tmp\mosquitto\mosquitto.conf
1544521568: mosquitto version 1.5.4 starting
1544521568: Config loaded from \tmp\mosquitto\mosquitto.conf.
1544521568: Opening ipv6 listen socket on port 1883.
1544521568: Opening ipv4 listen socket on port 1883.

sta utilizzando il config!
Ora connettiamo uno dei client, senza password

>>> c1 = Client("client_1")
>>> c1.connect("127.0.0.1", port=1883)
1544521703: New connection from 127.0.0.1 on port 1883.
1544521703: Sending CONNACK to 127.0.0.1 (0, 5)
1544521703: Socket error on client <unknown>, disconnecting.

come si nota, l’RC (return code) ottenuto nel tentativo di connessione è 5, che significa:
“The Client is not authorized to connect”.

Riproviamo fornendo le credenziali; per fare questo utilizziamo il metodo
username_pw_set(username=”roger”,password=”password”) della classe Client:
Per comodità assegnamo anche alla callback on_connect un nostra funzione di log, giusto per non
dover controllare il RC sul broker:

>>> def on_connect(client, userdata, flags, rc):
...     print("Connected flags: %s\nRC: %s" % (flags, rc))
... c1.on_connect = on_connect
>>> c1.username_pw_set(username="client_1", password="pwclient1")
>>> c1.connect("127.0.0.1", port=1883)
>>> c1.loop_start()
Connected flags: {'session present': 0}
RC: 0
>>> c1.disconnect()
>>> c1.loop_stop()
1544524189: New connection from 127.0.0.1 on port 1883.
1544524189: New client connected from 127.0.0.1 as client_1 (c1, k60, u'client_1').
1544524189: No will message specified.
1544524189: Sending CONNACK to client_1 (0, 0)
1544524190: Received DISCONNECT from client_1
1544524190: Client client_1 disconnected.

Queste sono dunque le prime nozioni di base del mondo mqtt. Per i dovuti approfindimenti,
fare riferimento alla documentazione ufficiale:

mqtt
paho-mqtt

altri link utili:
Steve Cope guide

Categorie:iot, mqtt, python Tag: , ,