Da appassionato di fumetti, non potevo non pubblicare un crossover tra il mio “storico” tutorial sull’uso del controller enc28j60 con Arduino e il nuovo tutorial sul protocollo MQTT.
Ecco quindi che, dopo aver introdotto il protocollo MQTT e spiegato l’uso di mosquitto, oggi vediamo come inviare dati ad un broker MQTT tramite il controller ethernet enc28j60.
Librerie
Utilizzeremo la libreria PubSubClient di Nick O’Leary per “parlare” con il nostro broker MQTT (mosquitto). La libreria può essere installata direttamente dal Library Manager di Arduino (menu Sketch – Include Library – Manage Libraries…):
La libreria scelta si basa sulla API Ethernet Client di Arduino, normalmente disponibile se si utilizza il chip ethernet “ufficiale” (W5100). Già in passato vi ho però parlato della libreria UIPEthernet che rende compatibili sketch e librerie scritte per tale chip anche per il chip enc28j60. Installiamo quindi anche questa libreria all’interno dell’IDE di Arduino e siamo pronti per scrivere il nostro sketch…
Infine per questo tutorial ho pensato di collegare un sensore di temperatura (e umidità) ad Arduino; il sensore scelto è il DHT11. Per leggere i valori dal sensore, utilizzeremo la libreria DHT sensor library di Adafruit, anch’essa installabile tramite il Library Manager.
Sketch
Ho pubblicato lo sketch completo nel mio repository Github.
Vediamo le parti principali. Dopo aver incluso le librerie, definiamo alcune costanti, tra le quali il topic al quale invieremo i dati, l’identificativo del nostro client MQTT, l’intervallo di invio dati e la configurazione del sensore:
#define CLIENT_ID "ArduinoMQTT" #define TOPIC "temperature" #define PUBLISH_DELAY 5000 #define DHTPIN 3 #define DHTTYPE DHT11 |
configuriamo quindi il MAC address dell’interfaccia di rete di Arduino e l’indirizzo IP del broker MQTT (= l’indirizzo del computer sul quale è in esecuzione mosquitto):
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; IPAddress mqttServer(192,168,1,4); |
la configurazione del client MQTT avviene indicando l’Ethernet client da utilizzare e il server (e la relativa porta) a cui connettersi:
mqttClient.setClient(ethClient); mqttClient.setServer(mqttServer, 1883); Serial.println(F("MQTT client configured")); |
all’interno del loop() controlliamo se è trascorso l’intervallo di tempo tra una misurazione e la successiva, in caso affermativo leggiamo il nuovo valore di temperatura e inviamolo al broker:
if(millis() - previousMillis > PUBLISH_DELAY) { sendData(); previousMillis = millis(); } |
molto importante chiamare frequentemente il comando loop() dell’oggetto MQTT Client, in modo che questo possa processare i vari pacchetti in ingresso:
mqttClient.loop(); |
float t = dht.readTemperature(); Serial.print("Temperature: "); Serial.println(t); if(mqttClient.connect(CLIENT_ID)) { mqttClient.publish(TOPIC, dtostrf(t, 6, 2, msgBuffer)); } |
Test
Per provare lo sketch, dobbiamo per prima cosa eseguire mosquitto sul nostro PC. Apriamo inoltre un secondo prompt dei comandi e lanciamo mosquitto_sub per sottoscrivere il topic temperature:
mosquitto_sub.exe -t temperature
Se ora eseguiamo lo sketch, dovremmo vedere i valori di temperatura inviati al broker e da questi al sottoscrittore:
Salve scusa mi rendo conto che il post è un po vecchiotto ma volevo chiedere se c’è un modo di sfruttare il protocollo mqtt senza lo shield ethernet, ho letto un po in giro e ho trovato la libreria per arduino SerialIp, ma è una libreria del 2010, volevo sapere se andava bene per arduino due, e se è una libreria valida.
Grazie
Ciao Vincenzo, la libreria SerialIP funziona ma richiede un PC collegato ad Arduino… non l’ho provata con Arduino Due
Scusate se rispondo solo ora ma sono stato fuori casa per lavoro, si lo che ci vuole un pc infatti pensavo di usarlo con un raspberry collegato tramite la seriale e quindi il raspi avrebbe fatto da gateway ip.
Pensi che sia possibile, e sarebbe facile da mettere su?
Grazie
Buona sera Luca, per prima cosa vorrei farti i complimenti, spero che sei consapevole che hai la migliore guida di tutto il web sull mqtt e arduino.
Ho un piccolo problema con questo sketch:
nel monitor seriale tutto ok
nel promp dove eseguo mosquitto sembra tutto ok
1504127457: Opening ipv6 listen socket on port 1883.
1504127457: Opening ipv4 listen socket on port 1883.
1504127497: New connection from ::1 on port 1883.
1504127497: New client connected from ::1 as mosqsub|14864-Hp-Cristi (c1, k60).
1504127497: Sending CONNACK to mosqsub|14864-Hp-Cristi (0, 0)
1504127497: Received SUBSCRIBE from mosqsub|14864-Hp-Cristi
1504127497: temp (QoS 0)
1504127497: mosqsub|14864-Hp-Cristi 0 temp
1504127497: Sending SUBACK to mosqsub|14864-Hp-Cristi
1504127557: Received PINGREQ from mosqsub|14864-Hp-Cristi
1504127557: Sending PINGRESP to mosqsub|14864-Hp-Cristi
ma nel promp dove eseguo il sub non ricevo nessun valore
Riesci ad aiutarmi.
Grazie in anticipo
Cristian, dai logs sembra che Arduino non stia spedendo nulla… vedi infatti che il sub si collega (“new client connected as mosqsub…”). Lo sketch che output ti da?
Buona sera Luca, questo è il log da seriale arduino:
MQTT Arduino Demo
MQTT Arduino Demo
Ethernet configured via DHCP
Ip address: 192.168.1.102
MQTT client configured
Dht sensor initialized
Ready to send data
la serie delle letture.
Io utilizzo la ethernet shield e non il modulo enc28j60, può cambiare qualcosa?
Ho notato che l’ip segnato sul log di arduino è lo stesso del server dove è in funzione mosquitto, ma dovrebbe essere l’ip preso con il dhcp giusto?
Grazie mille
Buona sera Luca, ho trovato il problema…i FIREWALL…se attivi su windows, bloccano, giustamente, le connessioni alla porta 1883.
Ora funziona tutto.
Grazie
Sei davvero un grande.
ottimo, grazie a te per aver condiviso la soluzione al tuo problema!
Hi Cristian, First of all thank you for sharing the issue.
I have the similar issue and i tried creating inbound and outbound rules in firewall to allow port 1883. But it did not work.
Could you share your findings
Thank you in advance
Buonasera Luca,
innanzitutto complimenti per il blog!
Sto provando ad utilizzare MQTT su un Arduino Nano e uno shield basato su ENC28J60. Nessun problema in fase di publish mentre continuo ad avere problemi nella lettura dei messaggi sul topic.
La callback viene correttamente scatenata con il topic valorizzato come mi aspetto mentre il valore della variabile “length” continua ad essere sempre 0, quindi payload vuoto.
Ho fatto vari test ma nulla.
Qualche consiglio?
P.S. Sto utilizzando PubSubClient e UIPEthernet.
Grazie mille in anticipo.
ciao Simone, molto strano… non ho mai avuto problemi a “leggere” un topic con quella libreria. Hai provato l’esempio incluso? Anche questo ti da sempre length=0?