[IoT] Bài 7: ESP8266 - Arduino Ide Và Giao Thức MQTT

Giao thức MQTT phù hợp nhất cho các dự án IoT thương mại, nó dáp ứng tốc độ tốt, băng thông ít, độ tin cậy cao. Tài liệu về giao thức MQTT thì các bạn tham khảo ở các trên mạng hoặc 1 số bài sau :

  • https://smartfactoryvn.com/technology/internet-of-things/giao-thuc-mqtt-la-gi-nhung-ung-dung-cua-mqtt-nhu-the-nao/
  • https://esp8266.vn/nonos-sdk/mqtt/what-is-mqtt/

Mình sẽ không nhắc lại phần lí thuyết nữa vì trên mạng có rất nhiều rồi. Chúng ta sẽ đi vào thực hành làm thử 1 project với giao thức MQTT luôn

Đầu tiên, phía esp8266 các bạn tải thư viện Pubsubclient

cai thu vien cho arduino
ADD thư viện vào

Giao thức MQTT cần có 1 server ( gọi là broker) để làm trung tâm của mọi luồng dữ liệu, trong các bài viết sau mình sẽ hướng dẫn các bạn tự build server, còn trong bài này mình sẽ sử dụng server miễn phí không bảo mật là broker.hivemq.com để demo

Các bạn copy chương trình cho esp8266

C #include <ESP8266WiFi.h> #include <PubSubClient.h> // Thông tin về wifi #define ssid "dieukhien" #define password "12345678" #define mqtt_server "broker.hivemq.com" const uint16_t mqtt_port = 1883; //Port của CloudMQTT TCP WiFiClient espClient; PubSubClient client(espClient); void setup() { Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); } // Hàm kết nối wifi void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } // Hàm call back để nhận dữ liệu void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Co tin nhan moi tu topic:"); Serial.println(topic); for (int i = 0; i < length; i++) Serial.print((char)payload[i]); Serial.println(); } // Hàm reconnect thực hiện kết nối lại khi mất kết nối với MQTT Broker void reconnect() { while (!client.connected()) // Chờ tới khi kết nối { // Thực hiện kết nối với mqtt user và pass if (client.connect("ESP8266_id1","ESP_offline",0,0,"ESP8266_id1_offline")) //kết nối vào broker { Serial.println("Đã kết nối:"); client.subscribe("IoT47_MQTT_Test"); //đăng kí nhận dữ liệu từ topic IoT47_MQTT_Test } else { Serial.print("Lỗi:, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Đợi 5s delay(5000); } } } unsigned long t; void loop() { if (!client.connected())// Kiểm tra kết nối reconnect(); client.loop(); if(millis() - t > 500) //nếu 500 mili giây trôi qua { t=millis(); Serial.print("Gui tin nhan \"Xin chao\" vao topic IoT47_MQTT_Test"); client.publish("IoT47_MQTT_Test", "Xin chao !"); // gửi dữ liệu lên topic IoT47_MQTT_Test } }
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 #include <ESP8266WiFi.h>#include <PubSubClient.h> // Thông tin về wifi#define ssid "dieukhien"#define password "12345678"#define mqtt_server "broker.hivemq.com"constuint16_t mqtt_port=1883;//Port của CloudMQTT TCP WiFiClient espClient;PubSubClient client(espClient); voidsetup(){Serial.begin(115200);setup_wifi();client.setServer(mqtt_server,mqtt_port);client.setCallback(callback);}// Hàm kết nối wifivoidsetup_wifi(){delay(10);Serial.println();Serial.print("Connecting to ");Serial.println(ssid);WiFi.begin(ssid,password);while(WiFi.status()!=WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("");Serial.println("WiFi connected");Serial.println("IP address: ");Serial.println(WiFi.localIP());}// Hàm call back để nhận dữ liệuvoidcallback(char*topic,byte*payload,unsignedintlength){Serial.print("Co tin nhan moi tu topic:");Serial.println(topic);for(inti=0;i<length;i++)Serial.print((char)payload[i]);Serial.println();}// Hàm reconnect thực hiện kết nối lại khi mất kết nối với MQTT Brokervoidreconnect(){while(!client.connected())// Chờ tới khi kết nối{// Thực hiện kết nối với mqtt user và passif(client.connect("ESP8266_id1","ESP_offline",0,0,"ESP8266_id1_offline"))//kết nối vào broker{Serial.println("Đã kết nối:");client.subscribe("IoT47_MQTT_Test");//đăng kí nhận dữ liệu từ topic IoT47_MQTT_Test}else{Serial.print("Lỗi:, rc=");Serial.print(client.state());Serial.println(" try again in 5 seconds");// Đợi 5sdelay(5000);}}}unsignedlongt;voidloop(){if(!client.connected())// Kiểm tra kết nốireconnect();client.loop();if(millis()-t>500)//nếu 500 mili giây trôi qua{t=millis();Serial.print("Gui tin nhan \"Xin chao\" vao topic IoT47_MQTT_Test");client.publish("IoT47_MQTT_Test","Xin chao !");// gửi dữ liệu lên topic IoT47_MQTT_Test}}
  • Ở dòng 5 và 6 các bạn đổi thành wifi của mình.
  • Hàm callback là hàm gọi lại khi có dữ liệu gửi đến topic mà chúng ta đăng kí
  • Hàm client.subscribe dùng để đăng kí 1 topic
  • Hàm client.publish dùng để gửi dữ liệu lên 1 topic
  • Hàm client.connect để kết nối vào MQTT Broker, với các tham sốESP8266_id1 : Id của thiết bị đăng kí vào (có thể chỉnh sửa bất thành bất kì)ESP_offline : khi thiết bị (esp8266) mất mạng (offline) thì broker sẽ xuất bản1 tin nhắn vào topic nàyESP8266_offline : Nội dung của tin nhắn offline

Sau khi kết nối thành công ở dòng 53 mình đăng kí topic IoT47_MQTT_Test và trong hàm loop xuất bản tin nhắn “Xin chao” vào chính topic IoT47_MQTT_Test .Như vậy chúng ta sẽ nhận lại được chính tin nhắn mà ta đã xuất bản !

giao thức mqtt esp8266

Kết quả: Mình đã nhận được chính tin nhắn mà mình xuất bản lên

Thiết kế giao diện web gửi tin nhắn cho ESP8266

Để có thể kết nối tới MQTT broker, mình sẽ sử dụng ngôn ngữ JavaScript và thư viện PahoMQTT

Các bạn tạo 1 file tên là index.html và thêm mã code web

C <!DOCTYPE html> <html> <head> <title>Demo MQTT</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script> <script type = "text/javascript" language = "javascript"> var max,at_OK; function makeid() { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; } // Create a client instance var client = new Paho.MQTT.Client("broker.hivemq.com", 8000, makeid()); // set callback handlers client.onConnectionLost = onConnectionLost; client.onMessageArrived = onMessageArrived; var options = { useSSL: false, userName: "", password: "", onSuccess:onConnect, onFailure:doFail } console.log("Connect to broker.hivemq.com:8000"); // connect the client client.connect(options); function doFail(e){ console.log(e); } function onConnect() //sự kiên kết nối thành công { console.log("Connect OK"); client.subscribe("IoT47_MQTT_Test"); //đăng kí kênh } // called when the client loses its connection function onConnectionLost(responseObject) { if (responseObject.errorCode !== 0) { console.log(responseObject.errorMessage); } } // called when a message arrives function onMessageArrived(message) { console.log(message.destinationName + ":" +message.payloadString); } function public (topic,data) { message = new Paho.MQTT.Message(data); message.destinationName = topic; client.send(message); } </script> </head> <body> </body> </html>
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 <!DOCTYPE html><html><head><title>Demo MQTT</title><meta name="viewport"content="width=device-width, initial-scale=1"><meta charset="utf-8"><script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js"type="text/javascript"></script><script type="text/javascript"language="javascript">varmax,at_OK;functionmakeid(){vartext="";varpossible="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for(vari=0;i<5;i++)text+=possible.charAt(Math.floor(Math.random()*possible.length)); returntext;}// Create a client instancevarclient=newPaho.MQTT.Client("broker.hivemq.com",8000,makeid()); // set callback handlersclient.onConnectionLost=onConnectionLost;client.onMessageArrived=onMessageArrived; varoptions={useSSL:false,userName:"",password:"",onSuccess:onConnect,onFailure:doFail} console.log("Connect to broker.hivemq.com:8000");// connect the clientclient.connect(options); functiondoFail(e){console.log(e);} functiononConnect()//sự kiên kết nối thành công{console.log("Connect OK");client.subscribe("IoT47_MQTT_Test");//đăng kí kênh } // called when the client loses its connectionfunctiononConnectionLost(responseObject){if(responseObject.errorCode!==0){console.log(responseObject.errorMessage);}} // called when a message arrivesfunctiononMessageArrived(message){console.log(message.destinationName+":"+message.payloadString);}functionpublic(topic,data){message=newPaho.MQTT.Message(data);message.destinationName=topic;client.send(message);}</script></head><body> </body></html>
  • Hàm makeID có nhiệm vụ tạo ra 1 id ngẫu nhiên để web kết nối tới MQTT broker tránh bị trùng id
  • Mình sẽ kết nối vào broker.hivemq.com qua cổng 8000 vì cổng 8000 là cổng dành cho các kết nối thông qua Socket, trong khi cổng 1883 dành cho các kết nối qua TCP
  • Hàm public dùng để xuất bản 1 tín nhắn tới 1 topic nào dó
  • Hàm client.subscribe dùng để đăng kí nhận tin nhắn từ 1 topic nào đó
  • Hàm onMessageArrived là hàm callback khi có 1 tin nhắn từ 1 topic đã đăng kí gửi tới

Mình sẻ lưu lại và mở file này bằng trình duyệt, sau đó ấn F12 để xem dữ liệu debug in ra màn hình console

giao thức mqtt esp8266

Các bạn có thể thấy sau khi thông báo Connect OK thì chúng ta đã nhận được tin nhắn “Xin chao !” mà esp8266 liên tục gửi lên mỗi 500 mili giây

Cũng trong màn hình debug, mình gõ hàm public để gửi thử dữ liệu đến esp8266 nhé !

giao thức mqtt esp8266
Gọi hàm public gửi dữ liệu
giao thức mqtt esp8266
ESP8266 đã nhận được tin nhắn xin chào

Thiết kế giao diện nút nhấn điều khiển thiết bị cho giao thức mqtt

Chúng ta sẽ tận dùng lại giao diện dã xài ở bài 5 nhé

C <!DOCTYPE html> <html> <head> <title>Demo MQTT</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script> <script type = "text/javascript" language = "javascript"> var max,at_OK; function makeid() { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; } // Create a client instance var client = new Paho.MQTT.Client("broker.hivemq.com", 8000, makeid()); // set callback handlers client.onConnectionLost = onConnectionLost; client.onMessageArrived = onMessageArrived; var options = { useSSL: false, userName: "", password: "", onSuccess:onConnect, onFailure:doFail } console.log("Connect to broker.hivemq.com:8000"); // connect the client client.connect(options); function doFail(e){ console.log(e); } function onConnect() //sự kiên kết nối thành công { console.log("Connect OK"); client.subscribe("ESP8266_sent_data"); //đăng kí kênh } // called when the client loses its connection function onConnectionLost(responseObject) { if (responseObject.errorCode !== 0) { console.log(responseObject.errorMessage); } } // called when a message arrives function onMessageArrived(message) { console.log(message.destinationName + ":" +message.payloadString); document.getElementById("tinnhan").innerHTML = "Tin nhắn từ esp8266: " + message.payloadString; } function public (topic,data) { message = new Paho.MQTT.Message(data); message.destinationName = topic; client.send(message); } </script> <style> .b{width: 100px;height: 40px;font-size: 21px;color: #FFF;background-color:#4caf50;border-radius: 10px;} .t{width: 100px;height: 40px;font-size: 21px;color: #FFF;background-color:#f44336;border-radius: 10px;} </style> </head> <body> <div style="width: 330px;height: auto;margin: 0 auto;margin-top: 70px"> <h1 align="center">Điều khiển thiết bị qua WIFI - MQTT</h1> <p align="center" id="tinnhan">Tin nhắn từ esp8266: ... </p> <table align="center"> <tr> <td><button class='b' onclick="public('ESP8266_read_data','Bật 1')">Bật 1</button><td> <td><button class='t' onclick="public('ESP8266_read_data','Tắt 1')">Tắt 1</button><td> <tr> <tr> <td><button class='b' onclick="public('ESP8266_read_data','Bật 2')">Bật 2</button><td> <td><button class='t' onclick="public('ESP8266_read_data','Tắt 2')">Tắt 2</button><td> <tr> <tr> <td><button class='b' onclick="public('ESP8266_read_data','Bật 3')">Bật 3</button><td> <td><button class='t' onclick="public('ESP8266_read_data','Tắt 3')">Tắt 3</button><td> <tr> <tr> <td><button class='b' onclick="public('ESP8266_read_data','Bật 4')">Bật 4</button><td> <td><button class='t' onclick="public('ESP8266_read_data','Tắt 4')">Tắt 4</button><td> <tr> </table> </div> </body> </html>
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 <!DOCTYPE html><html><head><title>Demo MQTT</title><meta name="viewport"content="width=device-width, initial-scale=1"><meta charset="utf-8"><script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js"type="text/javascript"></script><script type="text/javascript"language="javascript">varmax,at_OK;functionmakeid(){vartext="";varpossible="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for(vari=0;i<5;i++)text+=possible.charAt(Math.floor(Math.random()*possible.length)); returntext;}// Create a client instancevarclient=newPaho.MQTT.Client("broker.hivemq.com",8000,makeid()); // set callback handlersclient.onConnectionLost=onConnectionLost;client.onMessageArrived=onMessageArrived; varoptions={useSSL:false,userName:"",password:"",onSuccess:onConnect,onFailure:doFail} console.log("Connect to broker.hivemq.com:8000");// connect the clientclient.connect(options); functiondoFail(e){console.log(e);} functiononConnect()//sự kiên kết nối thành công{console.log("Connect OK");client.subscribe("ESP8266_sent_data");//đăng kí kênh } // called when the client loses its connectionfunctiononConnectionLost(responseObject){if(responseObject.errorCode!==0){console.log(responseObject.errorMessage);}} // called when a message arrivesfunctiononMessageArrived(message){console.log(message.destinationName+":"+message.payloadString);document.getElementById("tinnhan").innerHTML="Tin nhắn từ esp8266: "+message.payloadString; }functionpublic(topic,data){message=newPaho.MQTT.Message(data);message.destinationName=topic;client.send(message);}</script><style>.b{width:100px;height:40px;font-size:21px;color:#FFF;background-color:#4caf50;border-radius:10px;}.t{width:100px;height:40px;font-size:21px;color:#FFF;background-color:#f44336;border-radius:10px;}</style></head><body><div style="width: 330px;height: auto;margin: 0 auto;margin-top: 70px"><h1 align="center">Điukhinthiếtbqua WIFI-MQTT</h1><palign="center"id="tinnhan">Tin nhntesp8266:...</p><table align="center"><tr><td><button class='b'onclick="public('ESP8266_read_data','Bật 1')">Bt1</button><td><td><button class='t'onclick="public('ESP8266_read_data','Tắt 1')">Tt1</button><td><tr><tr><td><button class='b'onclick="public('ESP8266_read_data','Bật 2')">Bt2</button><td><td><button class='t'onclick="public('ESP8266_read_data','Tắt 2')">Tt2</button><td><tr><tr><td><button class='b'onclick="public('ESP8266_read_data','Bật 3')">Bt3</button><td><td><button class='t'onclick="public('ESP8266_read_data','Tắt 3')">Tt3</button><td><tr><tr><td><button class='b'onclick="public('ESP8266_read_data','Bật 4')">Bt4</button><td><td><button class='t'onclick="public('ESP8266_read_data','Tắt 4')">Tt4</button><td><tr></table></div></body></html>
Demo MQTT Điều khiển thiết bị qua WIFI - MQTT

Tin nhắn từ esp8266: ...

Bật 1 Tắt 1
Bật 2 Tắt 2
Bật 3 Tắt 3
Bật 4 Tắt 4

Khi ấn nút ( sự kiện OnClick) mình sẽ cho xuất bản tin nhắn tương ứng tới ESP8266 qua topic ESP8266_read_data. Do vậy ở code esp8266 mình sẽ sửa lại code cho nó đăng kí vào topic ESP8266_read_data và cho web đăng kí vào kênh ESP8266_sent_data để nhận tin nhắn esp8266 gửi lên

Sửa lại topic đăng kí của esp8266 thành ESP8266_read_data

Mình cũng thêm đoạn mã đọc data tử cổng Serial để gửi lên cho web

Full code cho esp8266

C #include <ESP8266WiFi.h> #include <PubSubClient.h> // Thông tin về wifi #define ssid "dieukhien" #define password "12345678" #define mqtt_server "broker.hivemq.com" const uint16_t mqtt_port = 1883; //Port của CloudMQTT TCP WiFiClient espClient; PubSubClient client(espClient); void setup() { Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); } // Hàm kết nối wifi void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } // Hàm call back để nhận dữ liệu void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Co tin nhan moi tu topic:"); Serial.println(topic); for (int i = 0; i < length; i++) Serial.print((char)payload[i]); Serial.println(); } // Hàm reconnect thực hiện kết nối lại khi mất kết nối với MQTT Broker void reconnect() { while (!client.connected()) // Chờ tới khi kết nối { // Thực hiện kết nối với mqtt user và pass if (client.connect("ESP8266_id1","ESP_offline",0,0,"ESP8266_id1_offline")) //kết nối vào broker { Serial.println("Đã kết nối:"); client.subscribe("ESP8266_read_data"); //đăng kí nhận dữ liệu từ topic ESP8266_read_data } else { Serial.print("Lỗi:, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Đợi 5s delay(5000); } } } void loop() { if (!client.connected())// Kiểm tra kết nối reconnect(); client.loop(); if(Serial.available() > 0) { delay(30); char inputString[30]=""; int i=0; while(Serial.available() > 0) { char inChar = (char)Serial.read(); inputString[i++] = inChar; } client.publish("ESP8266_sent_data", inputString); // gửi dữ liệu lên topic ESP8266_sent_data } }
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 #include <ESP8266WiFi.h>#include <PubSubClient.h> // Thông tin về wifi#define ssid "dieukhien"#define password "12345678"#define mqtt_server "broker.hivemq.com"constuint16_t mqtt_port=1883;//Port của CloudMQTT TCP WiFiClient espClient;PubSubClient client(espClient); voidsetup(){Serial.begin(115200);setup_wifi();client.setServer(mqtt_server,mqtt_port);client.setCallback(callback);}// Hàm kết nối wifivoidsetup_wifi(){delay(10);Serial.println();Serial.print("Connecting to ");Serial.println(ssid);WiFi.begin(ssid,password);while(WiFi.status()!=WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("");Serial.println("WiFi connected");Serial.println("IP address: ");Serial.println(WiFi.localIP());}// Hàm call back để nhận dữ liệuvoidcallback(char*topic,byte*payload,unsignedintlength){Serial.print("Co tin nhan moi tu topic:");Serial.println(topic);for(inti=0;i<length;i++)Serial.print((char)payload[i]);Serial.println();}// Hàm reconnect thực hiện kết nối lại khi mất kết nối với MQTT Brokervoidreconnect(){while(!client.connected())// Chờ tới khi kết nối{// Thực hiện kết nối với mqtt user và passif(client.connect("ESP8266_id1","ESP_offline",0,0,"ESP8266_id1_offline"))//kết nối vào broker{Serial.println("Đã kết nối:");client.subscribe("ESP8266_read_data");//đăng kí nhận dữ liệu từ topic ESP8266_read_data}else{Serial.print("Lỗi:, rc=");Serial.print(client.state());Serial.println(" try again in 5 seconds");// Đợi 5sdelay(5000);}}}voidloop(){if(!client.connected())// Kiểm tra kết nốireconnect();client.loop();if(Serial.available()>0){delay(30);charinputString[30]="";inti=0;while(Serial.available()>0){charinChar=(char)Serial.read();inputString[i++]=inChar;}client.publish("ESP8266_sent_data",inputString);// gửi dữ liệu lên topic ESP8266_sent_data}}
Demo kết quả

Related posts:

[IOT FULL STACK] Bài 1: Giới thiệu chip esp8266, điều khiển đèn led bật tắt[ENC28J60] Bài 14: Giao thức HTTP - Tạo Webserver với ENC28J60[ENC28J60] Bài 21: LWIP - Giao thức TCP với raw apiBảo mật chương trình cho esp8266

Từ khóa » Mqtt Với Esp8266