본문 바로가기

아두이노우노 R4

Node-Red IoT 대시보드 - 코딩이 필요 없습니다!

반응형

 

소개 이 게시물에서는 HTML/CSS/자바스크립트와 같은 저수준 코딩을 하지 않고도 나만의 사물 인터넷(IoT) 대시보드를 만들기 위해 Node-Red를 설정하여 Arduino 센서 수치를 표시하는 방법을 보여줍니다. 이 프로젝트의 비디오 데모 발표를 보려면 아래를 보거나 제 YouTube 채널에서 시청하세요. 

 

무엇을 구축할까요?

 

 

웹 개발 경험이 없는 경우 HTML/CSS/자바스크립트에 대한 지식이 필요하기 때문에 IoT 대시보드 개발이 사소하고 어렵게 느껴질 수 있습니다. 다행히도 Node-Red는 로우코드 브라우저 기반 프로그래밍 도구로, 코딩을 최소화하거나 전혀 하지 않고도 자체 사용자 인터페이스를 생성할 수 있습니다. 

 

 

이 글에서는 DHT22 센서 모듈을 읽는 ESP32 보드에서 나오는 센서 판독값을 처리하도록 Node-Red를 구성하겠습니다. Arduino 프레임워크로 ESP32를 프로그래밍하고 MQTT(MQ 원격 측정 전송)를 통해 메시지를 전송할 것입니다. 

 

Design 

 

 

위 이미지는 이 프로젝트의 전체 설계를 보여주며 다음 세 가지 주요 구성 요소로 이루어져 있습니다.

  • Arduino - 센서 판독값의 소스이며 이 경우 DHT22 센서를 사용하고 있습니다.
  • Mosquitto - MQTT 브로커
  • Node-Red - 센서 판독값을 MQTT를 통해 표시하는 플로우를 포함합니다.

 

이 게시물에서는 ESP32 보드와 DHT22 센서를 사용하여 Arduino 프레임워크를 사용하여 온도와 습도를 검색하고 MQTT 항목을 통해 전송했습니다.

 

센서 판독값은 MQTT 메시지를 통해 전송되고 Mosquitto 브로커에서 수신됩니다. Node-Red는 Arduino 코드에서 동일한 MQTT 토픽을 수신하도록 구성되며, 자동으로 업데이트되는 대시보드에 판독값을 표시하는 플로우를 가지고 있습니다. 

 

전제 조건

 

Node-Red 애플리케이션에 액세스할 수 있거나 직접 설정할 수 있어야 합니다. 저는 라즈베리 파이를 호스트로 사용하고 있으며 그 안에 Node-Red를 설치했습니다. 

 

How to install Node-Red on Raspberry Pi
How to install Node-Red on Windows or PC

 

또한 메시지를 게시할 수 있는 MQTT 브로커가 있어야 합니다. 저는 Windows 또는 PC 워크스테이션에서 Mosquitto MQTT 브로커를 사용하고 있습니다. 

 

Install Mosquitto MQTT Windows

 

아두이노 코드의 경우, 저는 PlatformIO 확장이 포함된 Visual Studio 코드를 사용했지만 원하는 경우 아두이노 IDE를 사용할 수도 있습니다. 

 

PlatformIO Tutorial for Arduino Development

 

 

필요한 부품/구성 요소 이 게시물을 따라 하려면 다음과 같은 부품과 구성 요소가 필요합니다: 

 

  • ESP32
  • 라즈베리 파이 4B
  • DHT22 센서 모듈
  • 브레드보드
  • 연결 전선

 

배선/스케매틱

 

 

위 이미지는 DHT22 센서와 Arduino ESP32 코드의 배선을 보여줍니다. 

 

ESP32 – Read DHT22 Sensor using Arduino

 

ESP32 아두이노 코드

 

이 프로젝트의 코드는 내 GitHub 리포지토리에서 zip 파일로 다운로드하거나 Git을 사용하여 복제할 수 있습니다. 다운로드가 완료되면 PlatformIO 확장이 설치된 Visual Studio Code에서 이 프로젝트를 엽니다. 

 

git clone https://github.com/donskytech/platformio-projects.git

cd esp32-projects/esp32-mqtt-dht22/

 

main.cpp 파일에는 로직의 핵심이 포함되어 있으며 다음과 같은 기능을 수행합니다.

WiFi에 연결

DHT22 센서 모듈 읽기

Mosquitto 브로커에 MQTT 메시지 게시

 

이 파일은 Mosquitto 브로커와 통신하여 MQTT 메시지를 Node-Red 애플리케이션에서 수신하고 실시간으로 비동기적으로 업데이트되는 그래픽 차트에 Arduino 센서 수치를 표시합니다.

 

이 게시물에서 저는 PubSubClient를 사용하여 Mosquitto MQTT 브로커와 통신했습니다. 이 라이브러리에 익숙하지 않거나 Arduino로 MQTT 브로커와 통신하는 방법에 대해 잘 모르신다면 아래 게시물을 참조하세요. 

 

MQTT Tutorial using Arduino Framework

 

#include <Arduino.h>
#include "DHT.h"
#include <WiFi.h>
#include <PubSubClient.h>

#define DHTPIN 32 // Digital pin connected to the DHT sensor

// Uncomment whatever type you're using!
// #define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22 // DHT 22  (AM2302), AM2321
// #define DHTTYPE DHT21   // DHT 21 (AM2301)

// Initialize DHT sensor.
DHT dht(DHTPIN, DHTTYPE);

// Change this to point to your Wifi Credentials
const char *ssid = "<REPLACE_ME_WITH_YOUR_SSID>";
const char *password = "<REPLACE_ME_WITH_YOUR_PASSWORD>";

// Your MQTT broker ID
const char *mqttBroker = "192.168.100.22";
const int mqttPort = 1883;

// MQTT topics
const char *temperatureTopic = "sensor/dht22/temperature";
const char *humidityTopic = "sensor/dht22/humidity";

// MQTT Client
WiFiClient espClient;
PubSubClient client(espClient);

#define MSG_BUFFER_SIZE (5)

// Cycle time
unsigned long previousMillis = 0;
const int interval = 2000;

// Callback function whenever an MQTT message is received
void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String message;
  for (int i = 0; i < length; i++)
  {
    Serial.print(message += (char)payload[i]);
  }
  Serial.println();
}

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");

    // Create a random client ID
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);

    // Attempt to connect
    if (client.connect(clientId.c_str()))
    {
      Serial.println("MQTT Broker connected!");
    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void publishMessage(const char *topic, float value)
{
  char msgBuffer[MSG_BUFFER_SIZE];
  snprintf(msgBuffer, MSG_BUFFER_SIZE, "%g", value);
  Serial.printf("Publishing to topic :: %s, value :: %s", topic, msgBuffer);
  Serial.println("");
  client.publish(topic, msgBuffer);
}

// Connect to Wifi
void setup_wifi()
{
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  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());
}

void setup()
{
  Serial.begin(115200);
  // Setup the wifi
  setup_wifi();
  // setup the mqtt server and callback
  client.setServer(mqttBroker, mqttPort);
  client.setCallback(callback);

  dht.begin();
}

void loop()
{
  if (!client.connected())
  {
    reconnect();
  }
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval)
  {
    // save the last time we send the last reading
    previousMillis = currentMillis;

    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    float humidity = dht.readHumidity();
    // Read temperature as Celsius (the default)
    float temperatureInC = dht.readTemperature();
    // Read temperature as Fahrenheit (isFahrenheit = true)
    float temperatureInF = dht.readTemperature(true);

    // Check if any reads failed and exit early (to try again).
    if (isnan(humidity) || isnan(temperatureInC) || isnan(temperatureInF))
    {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }
    publishMessage(temperatureTopic, temperatureInC);
    publishMessage(humidityTopic, humidity);
  }
}

 

코드의 각 줄이 무엇을 하는지 자세히 살펴보고 이해를 돕겠습니다. 

 

헤더 파일 가져오기 

 

#include <Arduino.h>
#include "DHT.h"
#include <WiFi.h>
#include <PubSubClient.h>

 

와이파이, DHT22 센서, MQTT 브로커와 통신하는 데 필요한 헤더 파일을 가져옵니다.

 

DHT 설정하기 

 

#define DHTPIN 32 // Digital pin connected to the DHT sensor

// Uncomment whatever type you're using!
// #define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22 // DHT 22  (AM2302), AM2321
// #define DHTTYPE DHT21   // DHT 21 (AM2301)

// Initialize DHT sensor.
DHT dht(DHTPIN, DHTTYPE);

 

DHT22 GPIO 핀을 정의하고 DHT22 센서 모듈과 통신하는 데 사용할 DHT 클래스의 인스턴스를 입력하고 생성합니다.

 

WiFi 및 MQTT 설정하기 

 

// Change this to point to your Wifi Credentials
const char *ssid = "<REPLACE_ME_WITH_YOUR_SSID>";
const char *password = "<REPLACE_ME_WITH_YOUR_PASSWORD>";

// Your MQTT broker ID
const char *mqttBroker = "192.168.100.22";
const int mqttPort = 1883;

 

이 변수에는 WiFi 네트워크 구성과 MQTT 브로커 IP 주소가 포함됩니다. 자신의 설정에 맞게 이 파일을 적절히 교체하세요. 

 

// MQTT topics
const char *temperatureTopic = "sensor/dht22/temperature";
const char *humidityTopic = "sensor/dht22/humidity";

// MQTT Client
WiFiClient espClient;
PubSubClient client(espClient);

#define MSG_BUFFER_SIZE (5)

// Cycle time
unsigned long previousMillis = 0;
const int interval = 2000;

 

DHT22 센서에서 나오는 각 센서 판독값에 대해

  • 센서/dht22/온도
  • 센서/dht22/습도

라는 두 개의 토픽을 생성했습니다.

 

다음으로, Mosquitto MQTT 브로커와 통신하는 데 사용할 PubSubClient 클래스의 인스턴스를 생성합니다. 마지막으로, 주기 시간을 2초로 설정하는데, 이는 DHT22 센서를 읽고 그 값을 MQTT 브로커로 전송하는 간격입니다. 

 

// Callback function whenever an MQTT message is received
void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String message;
  for (int i = 0; i < length; i++)
  {
    Serial.print(message += (char)payload[i]);
  }
  Serial.println();
}

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");

    // Create a random client ID
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);

    // Attempt to connect
    if (client.connect(clientId.c_str()))
    {
      Serial.println("MQTT Broker connected!");

    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

 

callback() 및 reconnect() 함수는 MQTT 브로커에서 오는 메시지에 응답하고 연결이 끊어질 경우 재연결하는 데 필요합니다. 

 

void publishMessage(const char *topic, float value)
{
  char msgBuffer[MSG_BUFFER_SIZE];
  snprintf(msgBuffer, MSG_BUFFER_SIZE, "%g", value);
  Serial.printf("Publishing to topic :: %s, value :: %s", topic, msgBuffer);
  Serial.println("");
  client.publish(topic, msgBuffer);
}

// Connect to Wifi
void setup_wifi()
{
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  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());
}

 

publicMessage() 함수는 브로커에 MQTT 메시지를 게시하는 데 사용되며, setup_wifi() 함수는 와이파이 네트워크에 연결하는 데 사용됩니다. 

 

setup() 

 

void setup()
{
  Serial.begin(115200);
  // Setup the wifi
  setup_wifi();
  // setup the mqtt server and callback
  client.setServer(mqttBroker, mqttPort);
  client.setCallback(callback);

  dht.begin();
}

 

이 함수는 Arduino 프로그램을 초기화하는 것이 주요 임무인 표준 setup() 함수이며, 이를 사용하여 다음과 같은 작업을 수행했습니다: 

 

  • 직렬 모니터 전송 속도를 설정합니다.
  • setup_wifi()를 사용하여 와이파이에 연결합니다.
  • MQTT 클라이언트를 위한 서버 및 콜백을 설정합니다.
  • DHT22 센서와 통신을 시작합니다. 

 

loop() 

 

void loop()
{
  if (!client.connected())
  {
    reconnect();
  }
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval)
  {
    // save the last time we send the last reading
    previousMillis = currentMillis;

    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    float humidity = dht.readHumidity();
    // Read temperature as Celsius (the default)
    float temperatureInC = dht.readTemperature();
    // Read temperature as Fahrenheit (isFahrenheit = true)
    float temperatureInF = dht.readTemperature(true);

    // Check if any reads failed and exit early (to try again).
    if (isnan(humidity) || isnan(temperatureInC) || isnan(temperatureInF))
    {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }
    publishMessage(temperatureTopic, temperatureInC);
    publishMessage(humidityTopic, humidity);
  }
}

 

 

여기에서 간격에 도달하면 DHT22 센서를 판독합니다. 또한 지정된 MQTT 주제를 통해 판독값을 게시하여 Node-Red가 대시보드를 업데이트하여 최신 Arduino DHT22 센서 판독값을 표시할 수 있도록 합니다. 

 

노드-레드 IoT 대시보드 

 

Node-Red IoT Arduino Dashboard

 

위 이미지는 MQTT를 통해 Arduino 센서 판독값을 표시하는 노드-레드 플로우를 보여줍니다. 이 모듈은 node-red-dashboard 모듈을 사용하여 센서 판독값을 텍스트 및 그래픽 차트로 표시하며 비동기적으로 자동으로 업데이트됩니다.

 

라이브러리를 설치하지 않은 경우 관리 팔레트로 이동하여 "node-red-dashboard"를 검색하여 라이브러리를 설치하세요. 

 

 

이 흐름은 제 GitHub 리포지토리에서도 확인할 수 있으며 아래에도 나와 있습니다. 

 

[{"id":"0b958bf98108ac7c","type":"ui_chart","z":"d4f46a5a0a4d81d6","name":"","group":"90ca17ebd42f9ffa","order":5,"width":11,"height":6,"label":"Temperature","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"50","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":690,"y":260,"wires":[[]]},{"id":"1935c2e04eeb79dc","type":"ui_chart","z":"d4f46a5a0a4d81d6","name":"","group":"90ca17ebd42f9ffa","order":8,"width":11,"height":6,"label":"Humidity","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"100","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":680,"y":480,"wires":[[]]},{"id":"076194cdb1d2a526","type":"ui_gauge","z":"d4f46a5a0a4d81d6","name":"","group":"90ca17ebd42f9ffa","order":6,"width":5,"height":5,"gtype":"gage","title":"Temperature","label":"Celcius","format":"{{value}}","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":690,"y":340,"wires":[]},{"id":"056796718e758a6b","type":"ui_gauge","z":"d4f46a5a0a4d81d6","name":"","group":"90ca17ebd42f9ffa","order":10,"width":5,"height":5,"gtype":"gage","title":"Humidity","label":"%","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":680,"y":520,"wires":[]},{"id":"2ef004bee1e74e95","type":"mqtt in","z":"d4f46a5a0a4d81d6","name":"","topic":"sensor/dht22/temperature","qos":"0","datatype":"utf8","broker":"abf7235cc1485ab2","nl":false,"rap":true,"rh":0,"inputs":0,"x":330,"y":280,"wires":[["0b958bf98108ac7c","076194cdb1d2a526","0c24b89fd0c850bd"]]},{"id":"e6fc867230945246","type":"mqtt in","z":"d4f46a5a0a4d81d6","name":"","topic":"sensor/dht22/humidity","qos":"0","datatype":"auto-detect","broker":"abf7235cc1485ab2","nl":false,"rap":true,"rh":0,"inputs":0,"x":320,"y":460,"wires":[["1935c2e04eeb79dc","056796718e758a6b","6f9b868542396b05"]]},{"id":"0c24b89fd0c850bd","type":"ui_text","z":"d4f46a5a0a4d81d6","group":"90ca17ebd42f9ffa","order":1,"width":6,"height":1,"name":"","label":"Temperature","format":"{{msg.payload}}","layout":"col-center","className":"","x":690,"y":180,"wires":[]},{"id":"6f9b868542396b05","type":"ui_text","z":"d4f46a5a0a4d81d6","group":"90ca17ebd42f9ffa","order":3,"width":6,"height":1,"name":"","label":"Humidity","format":"{{msg.payload}}","layout":"col-center","className":"","x":680,"y":420,"wires":[]},{"id":"90ca17ebd42f9ffa","type":"ui_group","name":"DHT22","tab":"451ab0586fb55eb3","order":1,"disp":true,"width":"16","collapse":false,"className":""},{"id":"abf7235cc1485ab2","type":"mqtt-broker","name":"Local Mosquitto Broker","broker":"192.168.100.22","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"451ab0586fb55eb3","type":"ui_tab","name":"Custom Dashboard","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

 

각 노드가 어떻게 구성되는지 살펴보겠습니다. 온도 및 습도 디스플레이는 거의 비슷하며 동일한 노드 세트를 사용하므로 온도만 살펴보겠습니다. 

 

MQTT In Node 

 

 

MQTT 인 노드는 내 Mosquitto MQTT 브로커를 수신하도록 구성되었으며 토픽을 sensor/dht22/temperature로 설정했습니다. 습도의 경우 sensor/dht22/humidity로 설정되어 있으며 이는 Arduino 코드와 일치해야 합니다. 

 

Text Node 

 

 

텍스트 노드는 온도와 습도 모두에 대한 DHT22 센서 판독값을 표시하도록 구성됩니다. 

 

Chart Node 

 

 

기록 차트를 표시하려면 다음 구성의 차트 노드가 필요합니다. 

 

Guage Node

 

 

게이지 노드는 다음과 같은 정보로 구성됩니다.

 

텍스트, 차트, 게이지 노드는 구성된 토픽을 수신하는 MQTT In 노드로부터 모든 데이터를 수신합니다. MQTT 브로커가 메시지를 보내면 MQTT In 노드가 페이로드를 전송하여 자동으로 표시합니다.

 

이것이 Node-Red 코드의 전부이며, 보시다시피 사용자 정의 코드를 추가하지 않고 Node-Red 대시보드 노드를 드래그하여 서로 연결하기만 했습니다. 

 

노드-레드 대시보드에서 레이아웃을 조정하는 방법은 무엇인가요? 

 

 

레이아웃을 변경하려면 대시보드 레이아웃 편집기로 이동하여 다음 노드의 배열 방식을 변경합니다.

 

마무리

 

이 게시물에서는 HTML/CSS/자바스크립트 코드를 프로그래밍하지 않고도 노드-레드 IoT 대시보드에 Arduino 센서 판독값을 성공적으로 표시했습니다. 노드-레드 대시보드를 사용하면 사용자 인터페이스 생성이 크게 간소화됩니다. 무언가를 배웠기를 바랍니다! 즐거운 탐험 되세요! 제 글이 마음에 드셨다면 이 글을 공유해 주세요. 고마워요! 

 

 

튜토리얼 원본 문서 

유튜브 강의 영상

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^