ESP32 Node Red MQTT – Cách hiển thị dữ liệu từ nhiều cảm biến

Trong hướng dẫn này, chúng ta sẽ cùng tìm hiểu về chủ đề ESP32 Node Red. Cụ thể, chúng ta sẽ đọc dữ liệu từ nhiều cảm biến khác nhau và hiển thị chúng qua Node Red với ESP32 MQTT, dựa trên phần mềm Arduino IDE.

Bạn sẽ tìm hiểu cách kết nối MQTT với ESP32 và Node Red để xuất bản và đăng ký một kênh MQTT. Khi đó, ESP32 MQTT là một nhà xuất bản và Node Red giống như một nhà đăng ký.

Danh sách cảm biến mình dùng trong chủ đề này là cảm biến nhiệt độ SD18B20, BME280 và DHT. Tất cả dữ liệu từ những cảm biến này sẽ được hiển thị trên Dashboard như hình dưới:

ESP32 Node Red MQTT - Gửi dữ liệu lên Dashboard
ESP32 Node Red MQTT – Gửi dữ liệu lên Dashboard

Chúng ta sẽ dùng Mosquitto broker (được cài trên Raspberry Pi). Nếu bạn không có mạch này, bạn cũng có thể cài chúng trên các thiết bị chạy hệ điều hành Linux Ubuntu hoặc Windows nhé!

Cả nhà xuất bản lẫn nhà đăng ký đều được kết nối với nhau qua giao thức MQTT được cài trên Raspberry Pi. Sau đó, ESP32 sẽ xuất bản dữ liệu từ cảm biến đến giao diện Node Red để chúng ta quan sát.

Cách ESP32 Node Red MQTT gửi dữ liệu với nhau

Sơ đồ bên dưới thể hiện quá trình hoạt động của hệ thống, khi chúng ta thực hiện dự án ESP32 Node Red MQTT này, theo mô hình Publisher (nhà xuất bản) – Subscriber (nhà đăng ký), với nhiều cảm biến khác nhau:

Sơ đồ minh họa cách ESP32 Node Red MQTT gửi dữ liệu với nhau

Cụ thể như sau:

  1. Một mạch ESP32 kết nối bằng dây với các cảm biến DHT22, DS18B20 và BME280. ESP32 này sẽ kết nối với giao thức MQTT, chúng ta sẽ dùng Mosquitto broker trên Raspberry Pi.
  2. Mạch ESP32 này xuất bản giá trị nhiệt độ đọc được từ DHT22 lên chủ đề MQTT có tên là esp32/dht/temperature và xuất bản độ ẩm lên esp32/dht/humidity.
  3. Tương tự, chúng xuất bản nhiệt độ từ BME280 lên esp32/bme280/temperature, độ ẩm từ chúng lên esp32/bme280/humidity và áp suất lên esp32/bme280/pressure.
  4. Tương tự, chúng xuất bản nhiệt độ theo thang đo C từ DS18B20 lên esp32/ds18b20/temperatureC và nhiệt độ theo thang đo F lên esp32/ds18b20/temperatureF
  5. Chúng ta sẽ dùng Node Red như một đơn vị hỗ trợ đăng ký 7 chủ đề này. Node Red nhận dữ liệu từ cảm biến và hiển thị chúng cho những thiết bị đăng ký chủ đề này (Tương tự như khi ta đăng ký kênh trên Youtube và nhận được thông báo về kênh khi có video mới).

Giao thức MQTT là gì?

  • MQTT là giao thức truyền thông gọn nhẹ, hỗ trợ nhiều thiết bị giao tiếp với nhau một cách nhanh chóng và đơn giản.
  • MQTT sử dụng mô hình giao tiếp Publish / Subscribe, hoạt động dựa trên từng chủ đề.

>> TÌm hiểu kỹ hơn về MQTT tại: MQTT vs HTTP trong IoT – Điểm khác biệt và các lưu ý khi chọn

Chuẩn bị

  • ESP32
  • DHT22
  • Điện trở 10k Ohm
  • BME280
  • DS18B20
  • Điện trở 4,7k Ohm
  • Dây Jumper
  • Breadboard

Kết nối phần cứng

1. DHT22:

  • Kết nối VCC của DHT22 với chân 3,3V hoặc VIN của ESP32
  • Kết nối chân Data với GPIO15 của ESP32 (đồng thời kết nối với điện trở 10k Ohm). Điện trở này giúp nâng cao chân Data để phù hợp với việc giao tiếp với những vi điều khiển như ESP32.
  • Chân thứ 3: Không sử dụng
  • Kết nối chân GND của DH22 với chân Ground của ESP32

2. BME280

BME280ESP32
VCC3.3V
GroundGround
SDASDA (GPIO21)
SCLSCL (GPIO22)

3. DS18B20

Bạn có thể kết nối bất kỳ chân GPIO nào của ESP32 với cảm biến này. Bạn có thể tìm hiểu về bài viết ESP32 GPIO trên Website IoTZone để hiểu hơn về sơ đồ các chân này.

Sơ đồ kết nối dự án ESP32 Node Red

Cài đặt thư viện

Để làm việc với DHT22, bạn cần cài thư viện DHT sensor. Để thực hiện, bạn click mở Sketch > Library > Manage Libraries, tìm kiếm tên thư viện và bắt đầu cài đặt.

Cài thư viện cho dự án ESP32 Node Red MQTT

Ngoài ra, bạn cũng cần cài thư viện  Adafruit Unified Sensor (theo cách tương tự như trên).

Với cảm biến SD18B20, bạn cần cài thư viện sau với cách tương tự như trên:

  • OneWire
  • DallasTemperature

Với BME280, bạn cần cài:

  • Adafruit_BME280
  • Adafruit_Sensor

Ngoài ra, chúng ta cũng cần thư viện Async MQTT Client Library và thư viện Async TCP. Bạn click lần lượt vào từng link mình đã gắn ở tên thư viện để tải chúng về, sau đó giải nén và di chuyển chúng vào thư mục chứa thư viện của Arduino IDE.

Sau khi cài xong tất cả thư viện trên, bạn khởi động lại Arduino IDE.

Code để ESP32 xuất bản dữ liệu

Bạn sử dụng đoạn code sau, nhớ thay đổi thông tin mạng WiFi của bạn và địa chỉ IP của mạch Raspberry Pi bạn đang dùng. Code sau giúp ESP32 xuất bản data lên MQTT, theo các bước:

  • Kết nối ESP32 với mạng WiFi của bạn
  • Khai báo các cảm biến với ESP32
  • Kết nối ESP32 với giao thức MQTT
  • Xuất bản dữ liệu lên chủ đề MQTT
#include "DHT.h"
#include <WiFi.h>
extern "C" {
  #include "freertos/FreeRTOS.h"
  #include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <OneWire.h>
#include <DallasTemperature.h>

//replace with your network credentials
#define WIFI_SSID "PTCL-08"
#define WIFI_PASSWORD "44332211"

// Raspberry Pi Mosquitto MQTT Broker
#define MQTT_HOST IPAddress(192, 168, 10, 8)
#define MQTT_PORT 1883

//MQTT Topics
#define MQTT_PUB_TEMP_DHT "esp32/dht/temperature"
#define MQTT_PUB_HUM_DHT  "esp32/dht/humidity"

#define MQTT_PUB_TEMP_BME280 "esp32/bme280/temperature"
#define MQTT_PUB_HUM_BME280  "esp32/bme280/humidity"
#define MQTT_PUB_PRES_BME280 "esp32/bme280/pressure"

#define MQTT_PUB_TEMP_C "esp32/ds18b20/temperatureC"
#define MQTT_PUB_TEMP_F "esp32/ds18b20/temperatureF"

#define DHTPIN 15  
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);

Adafruit_BME280 bme;

const int SensorDataPin = 4;   
  
OneWire oneWire(SensorDataPin);
DallasTemperature sensors(&oneWire);

float temperature_DHT, humidity_DHT; //variables for DHT
float temperature_BME280, humidity_BME280, pressure_BME280;   //variables for BME280
float temperature_Celsius, temperature_Fahrenheit;  //variables for DS18B20

AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;

unsigned long previousMillis = 0;   
const long interval = 10000;        

void connectToWifi() {
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void connectToMqtt() {
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
}

void WiFiEvent(WiFiEvent_t event) {
  Serial.printf("[WiFi-event] event: %dn", event);
  switch(event) {
    case SYSTEM_EVENT_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); 
      xTimerStart(wifiReconnectTimer, 0);
      break;
  }
}

void onMqttConnect(bool sessionPresent) {
  Serial.println("Connected to MQTT.");
  Serial.print("Session present: ");
  Serial.println(sessionPresent);
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  Serial.println("Disconnected from MQTT.");
  if (WiFi.isConnected()) {
    xTimerStart(mqttReconnectTimer, 0);
  }
}

void onMqttPublish(uint16_t packetId) {
  Serial.print("Publish acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void setup() {
  Serial.begin(115200);
  Serial.println();

  dht.begin();
  delay(1000);

  if (!bme.begin(0x76)) {
    Serial.println("Could not detect a BME280 sensor, Fix wiring connections!");
    while (1);
  }
  delay(1000);

  sensors.begin();
  delay(1000);
  
  mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
  wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));

  WiFi.onEvent(WiFiEvent);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onPublish(onMqttPublish);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  connectToWifi();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    //Read from DHT
    humidity_DHT = dht.readHumidity();
    temperature_DHT = dht.readTemperature();
    
    if (isnan(temperature_DHT) || isnan(humidity_DHT)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }
    //delay(3000);

    //Read from BME280
    temperature_BME280 = bme.readTemperature();
    humidity_BME280 = bme.readHumidity();
    pressure_BME280 = bme.readPressure() / 100.0F;
    //delay(3000);

    //Read from DS18B20
    sensors.requestTemperatures(); 
    temperature_Celsius = sensors.getTempCByIndex(0);
    temperature_Fahrenheit = sensors.getTempFByIndex(0);
    //delay(3000);
    
    // Publish an MQTT message on topic esp32/dht/temperature
    uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP_DHT, 1, true, String(temperature_DHT).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_DHT, packetIdPub1);
    Serial.printf("Message: %.2f \n", temperature_DHT);

    // Publish an MQTT message on topic esp32/dht/humidity
    uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM_DHT, 1, true, String(humidity_DHT).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM_DHT, packetIdPub2);
    Serial.printf("Message: %.2f \n", humidity_DHT);

        // Publish an MQTT message on topic esp32/bme280/temperature
    uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_TEMP_BME280, 1, true, String(temperature_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_BME280, packetIdPub3);
    Serial.printf("Message: %.2f \n", temperature_BME280);

    // Publish an MQTT message on topic esp32/bme280/humidity
    uint16_t packetIdPub4 = mqttClient.publish(MQTT_PUB_HUM_BME280, 1, true, String(humidity_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM_BME280, packetIdPub4);
    Serial.printf("Message: %.2f \n", humidity_BME280);

    
    // Publish an MQTT message on topic esp32/bme280/pressure
    uint16_t packetIdPub5 = mqttClient.publish(MQTT_PUB_PRES_BME280, 1, true, String(pressure_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_PRES_BME280, packetIdPub5);
    Serial.printf("Message: %.2f \n", pressure_BME280);

    // Publish an MQTT message on topic esp32/ds18b20/temperatureC
    uint16_t packetIdPub6 = mqttClient.publish(MQTT_PUB_TEMP_C, 1, true, String(temperature_Celsius).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_C, packetIdPub6);
    Serial.printf("Message: %.2f \n", temperature_Celsius);

    // Publish an MQTT message on topic esp32/ds18b20/temperatureF
    uint16_t packetIdPub7 = mqttClient.publish(MQTT_PUB_TEMP_F, 1, true, String(temperature_Fahrenheit).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_TEMP_F, packetIdPub7);
    Serial.printf("Message: %.2f \n", temperature_Fahrenheit);
  }
}

Demo kết quả

Sau khi chỉnh sửa các thông tin như mạng WiFi và địa chỉ IP của mạng Raspberry Pi, bạn click vào nút RST / EN trên ESP32 và mở Serial Monitor.

Trên Serial sẽ hiển thị thông tin là ESP32 đã kết nối với WIFi và Broker, dữ liệu cũng được gửi lên chủ đề tương ứng.

Cấu hình giao diện Node Red để hiển thị dữ liệu

Đầu tiên, bạn cần cài Node Red trên mạch Raspberry Pi. Chúng ta cần dịa chỉ IP của mạch Raspberry Pi và số cổng mà Node Red truy cập được (mặc định là 1880).

Bạn mở trình duyệt Web và nhập địa chỉ IP của mạch kèm theo số cổng, ví dụ: 192.168.18.8:1880

Tạo flow

Đây là giao diện của Node Red, bạn có thể bắt đầu bằng bước tạo Flow. Chúng ta sẽ tạo các tab, mình sẽ tạo 1 tab tên là Home như hình:

Tạo tab trên giao diện Node Red

Bước tiếp theo là tạo các Widgets. Chúng ta sẽ thêm nhóm (group) trên tab, mỗi nhóm cho 1 cảm biến:

Cảm biến DHT

Tạo group trên NOde Red

Kéo vả thả 2 gauges và 2 mqtt vào giao diện như hình:

Tạo widget trên NOde Red

Click đúp vào mqtt đầu tiên và chỉnh sửa thông số như hình dưới:

Tạo widget trên NOde Red

Thực hiện tương tự với các phần còn lại.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *