IoT-Ep6 | Sử dụng giao thức MQTT với Thingspeak
Trong bài viết này, chúng ta sẽ tìm hiểu cách sử dụng phương thức MQTT để cập nhật dữ liệu cảm biến trên Thingspeak. Các bạn có thể theo dõi video-demo hoặc bài hướng dẫn dưới đây.
Mục lục
1. Giới thiệu
Hiện nay, với phần lớn người dùng các ứng dụng WEB thì giao thức HTTP(s) luôn được dùng để truyền tải thông tin giữa các thiết bị. Tuy nhiên, sự phát triển công nghệ ngày nay mang tới nhiều ứng dụng và thiết bị khác nhau hơn mà ở đó các thiết bị yêu cầu độ trễ thấp và tiêu thụ ít năng lượng hơn. Phần lớn trong số thiết bị đó thuộc vào các nhóm ứng dụng Internet vạn vật (Internet of Things - IoT). Từ phiên bản đầu tiên năm 1996 cho tới hiện nay thì giao thức HTTP luôn được sử dụng trong hầu hết các ứng dụng có sử dụng trình duyệt WEB. Nhưng có lẽ là không cần thiết với độ lớn của Headers trong gói tin HTTP khi thiết bị IoT cần ít tài nguyên hơn để gửi tin nhắn tới máy chủ từ xa.
Để giảm bớt các gói tin dịch vụ và độ lớn của Headers trong giao thức HTTP, một giao thức khác có tên là MQTT (Message Queuing Telemetry Transport) được phát triển cho phép các thiết bị mạng hoạt động trong mô hình TCP/IP cũng có thể trao đổi tin nhắn với nhau và đỡ tốn tài nguyên mạng hơn.
2. Giao thức MQTT
2.1. Giao thức MQTT
MQTT là một giao thức xây dựng theo mô hình Publish/Subsribe được phát triển dành cho các thiết bị có hạn chế về năng lượng và băng thông truyền tải qua mạng không dây. Đây được coi là một giao thức đơn giản chạy trên TCP/IP sockets hoặc WebSockets. Cũng giống với HTTP thì giao thức MQTT cũng có thể được bảo mật bằng cách sử dụng thêm giao thức SSL. Mô hình Publish/Subsribe cho phép các tin nhắn được chuyển liên tục tới các Client khác mà không cần gửi yêu cầu thường xuyên tới máy chủ. Khác với mô hình Request/Response trong HTTP, các Client muốn nhận thông tin thì cần Subsribe (đăng ký) theo dõi một kênh trên Broker. Trên Hình 1 mô tả đơn giản 1 ví dụ cách giao tiếp các thiết bị theo giao thức MQTT.
- Broker: đây là máy chủ (Server), thiết bị chuyển tiếp tin nhắn giữa các thiết bị dựa theo topic mà thiết bị đó publish (gửi) vào hoặc subsribe (đăng ký) theo dõi topic đó.
- Publisher: đây là thiết bị sẽ gửi tin nhắn đi và gửi tới một topic riêng. Giả sử trên hình mô-đun NodeMCU là Publisher sẽ gửi dữ liệu nhiệt độ và độ ẩm tới topic “/topic_weather”.
- Subsriber: đây là thiết bị muốn theo dõi, muốn nhận tin nhắn từ thiết bị khác thông qua Broker. Thiết bị này nếu muốn nhận tin về nhiệt độ và độ ẩm từ mô-đun NodeMCU, thì các thiết bị này cần phải subsribe (đăng ký) tới topic “/topic_weather”. Sau khi đăng ký thành công, mỗi khi NodeMCU gửi đi tin nhắn mới thì Broker sẽ ngay lập tức gửi tới các thiết bị mà đã đăng ký topic “/topic_weather”.
Hình 1. Mô hình giao tiếp qua MQTT
Ngoài ra, tin nhắn gửi đi theo MQTT có thể được cài đặt tương ứng với yêu cầu chất lượng dịch vụ QoS (Quality of Service). Chúng ta sẽ tìm hiểu chi tiết về giao thức MQTT ở phần sau.
2.2. Sử dụng MQTT với Thingspeak
ThingSpeak cung cấp đại chỉ URL của Broker tại mqtt3.thingspeak.com. Cấu hình cho Client muốn kết nối qua MQTT có thể như sau:
Cổng | Kiểu kết nối | Mã hoá |
---|---|---|
1883 | TCP | Không |
8883 | TCP | TLS/SSL |
80 | Websocket | Không |
443 | Wbsocket | TLS/SSL |
Có 2 cách MQTT Publish để cập nhật dữ liệu trên Channel của Thingspeak.
MQTT Publish | Topic | Payload |
Publish tới nhiều trường cùng lúc | channels/<channelID>/publish | field1=<value1>&field2=<value2> |
Publish 1 giá trị tới một trường dữ liệu | channels/<channelID>/publish/fields/field<fieldNumber> | <value> |
Trong bài viết này, chúng ta sẽ gửi dữ liệu nhiệt độ và độ ẩm lên các trường field1 và field2 cùng một lúc. Để kết nối tới Thingspeak qua MQTT, chúng ta cần tạo thiết bị MQTT. Các bước khởi tạo thiết bị như sau:
1. Theo Hình 2, trên Menu của Website, chúng ta nhấn vào Devices –> MQTT.
Hình 2. Tạo thiết bị MQTT
2. Nhấn vào Add a new device để thêm 1 thiết bị. Sau đó, chúng ta sẽ điền các thông tin cho thiết bị được khởi tạo, và cho phép thiết bị truy cập tới kênh (Channel) mà chúng ta muốn cập nhật dữ liệu (Hình 3).
Hình 3. Tạo thiết bị MQTT
3. Sau khi nhấn vào Add Device ở trên Hình 3, chúng ta nhận được sửa sổ cho chúng ta có thông tin đăng nhập MQTT để publish và subsribe tới Thingspeak. Ở đây, chúng ta có thể Download file mqtt_secrets.h cho lập trình trên Arduino (Hình 4).
Hình 4. Thông tin kết nối cho thiết bị qua MQTT
3. Kết nối và lập trình
Trong bài này, chúng ta tiếp tục làm việc với NodeMCU và DHT22. Cảm biến có thể được kết nối tới mô-đun NodeMCU theo sơ đồ Hình 5.
Hình 5. Sơ đồ kết nối NodeMCU với DHT22
Tiếp theo, chúng ta mở chương trình Arduino IDE để viết code cho NodeMCU. Trước tiên, chúng ta sẽ cần vào phần quản lý thư viện qua Tools –> Manage Libraries. Sau đó, tìm kiếm thư viện EspMQTTClient và cài đặt thư viện này cùng các thư viện liên quan (Hình 6).
Hình 6. Cài đặt thư viện EspMQTTClient
Các bạn có thể tham khảo bài code tại đây
Hoặc bạn có thể copy đoạn code dưới đây vào Arduino IDE.
#include "EspMQTTClient.h"
#include "mqtt_secrets.h"
#include "DHT.h"
EspMQTTClient client(
SECRET_WIFI_NAME,
SECRET_WIFI_PASSWORD,
"mqtt3.thingspeak.com", // MQTT Broker server ip
SECRET_MQTT_USERNAME, // Can be omitted if not needed
SECRET_MQTT_PASSWORD, // Can be omitted if not needed
SECRET_MQTT_CLIENT_ID // Client name that uniquely identify your device
);
// DHT information
#define DHTPIN D2
#define DHTTYPE DHT22 // or set DHT11 type if you use DHT11
DHT dht(DHTPIN, DHTTYPE);
unsigned long lastTime = 0;
unsigned long delayTime = 20000; // set a period of sending data.
void setup() {
Serial.begin(115200);
// Begin DHT
dht.begin();
}
void onConnectionEstablished() {
Serial.println("MQTT Client is connected to Thingspeak!");
}
void publishData() {
if (client.isConnected() && (millis() - lastTime > delayTime)) {
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
Serial.print(F("\nTemperature: "));
Serial.print(t);
Serial.print(F("°C "));
Serial.print(F("Humidity: "));
Serial.print(h);
Serial.println(F("% "));
Serial.println(F("\nPublising data to Thingspeak"));
String MY_TOPIC = "channels/" + String(CHANNEL_ID) + "/publish"; // build your topic: channels/<channelID>/publish
String payload = "field1=" + String(t) + "&field2=" + String(h);
client.publish(MY_TOPIC, payload);
lastTime = millis();
}
}
void loop() {
client.loop();
publishData();
}
Sau khi lưu file Arduino trên ổ lưu trữ. Chúng ta sẽ cần chuyển file mqtt_secretss.h vào thư mục chứa file Arduino mà chúng ta vừa lưu. Hoặc bạn cũng thể tạo thêm file trong project (Hình 7) và đặt tên là mqtt_secrets.h.
Hình 7. Tạo thêm file trên Arduino
Trong file mqtt_secrets.h các bạn sẽ cần điền các thông tin kết nối như sau.
#define SECRET_MQTT_USERNAME "YOUR_MQTT_USERNAME"
#define SECRET_MQTT_CLIENT_ID "YOUR_MQTT_CLIENT_ID"
#define SECRET_MQTT_PASSWORD "YOUR_MQTT_PASSWORD"
#define SECRET_WIFI_NAME "YOUR_WIFI_NAME"
#define SECRET_WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
#define CHANNEL_ID "YOUR_CHANNEL_ID"
Chúng ta cùng nhìn qua về ý nghĩa của các dòng code ở trên.
Đầu tiên thì chúng ta sẽ cần tới các thư viện để sử dụng WIFI, MQTT, và cảm biến DHT.
#include "EspMQTTClient.h"
#include "mqtt_secrets.h"
#include "DHT.h"
Sau đó là khởi tạo một đối tượng client cho phép quản lý kết nối bao gồm kết nối WiFi, kết nối qua MQTT bằng cách sử dụng thư viện ESPMQTTClient.h.
EspMQTTClient client(
SECRET_WIFI_NAME,
SECRET_WIFI_PASSWORD,
"mqtt3.thingspeak.com", // MQTT Broker server ip
SECRET_MQTT_USERNAME, // Can be omitted if not needed
SECRET_MQTT_PASSWORD, // Can be omitted if not needed
SECRET_MQTT_CLIENT_ID // Client name that uniquely identify your device
);
Ngoài các hàm cơ bản ra, chúng ta có thêm hàm onConnectionEstablished() được gọi tới sau khi kết nối thành công tới Thingspeak.
void onConnectionEstablished() {
Serial.println("MQTT Client is connected to Thingspeak!");
}
Tiếp theo là hàm publishData() cho phép gửi dữ liệu đi với chu kỳ 20s.
void publishData() {
if (client.isConnected() && (millis() - lastTime > delayTime)) {
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
Serial.print(F("\nTemperature: "));
Serial.print(t);
Serial.print(F("°C "));
Serial.print(F("Humidity: "));
Serial.print(h);
Serial.println(F("% "));
Serial.println(F("\nPublising data to Thingspeak"));
String MY_TOPIC = "channels/" + String(CHANNEL_ID) + "/publish"; // build your topic: channels/<channelID>/publish
String payload = "field1=" + String(t) + "&field2=" + String(h);
client.publish(MY_TOPIC, payload);
lastTime = millis();
}
}
Trong hàm loop(), đối tượng client được gọi với loop() để luôn kiểm tra tính kết nối của thiết bị, và hàm publishData() được gọi tới để publish dữ liệu nhiệt độ và độ ẩm đo được tới topic.
void loop() {
client.loop();
publishData();
}
Sau khi upload chương trình lên NodeMCU, chúng ta có thể theo dõi một số thông tin được in ra Serial Monitor. Cùng với đó, dữ liệu cũng được cập nhật trên Thingspeak (Hình 8).
Hình 8. Màn hình Serial Monitor
4. Kết luận
Trong bài viết này, chúng ta cùng tìm hiểu qua về nguyên tắc hoạt động của giao thức MQTT và cách cập nhật các trường dữ liệu trên Channel của Thingspeak. Giao thức MQTT được cho là một trong những giao thức đơn giản phổ biến hiện nay được dùng cho các thiết bị IoT. Chúng ta cũng có thể thấy rằng, việc lập trình cho publish dữ liệu cũng đơn giản hơn so với khi sử dụng giao thức HTTP. Tuy nhiên vẫn còn có những nhược điểm của giao thức MQTT mà trong bài viết này chưa đề cấp tới, mà sẽ được tổng hợp ở một bài viết khác.