본문 바로가기

카테고리 없음

AIOT - MQTT + WeMos보드로 LED 제어하기

오늘은 MQTT를 활용하여 위모스 보드에서 브로커로부터 전달된 토픽을 읽어들이고, 그때 그때 LED의 온오프를 제어할 수 있는 프로그램을 만들어 보겠습니다.

 

예제의 내용은 다음과 같습니다.

 

1. 노드 서버에서 제공하는 index.html에 버튼이 두 개 나타나도록 한다.
하나는 LED 켜기 버튼, 하나는 LED 끄기 버튼
=> 켜기 버튼의 메시지명은 "led_on_event"
=> 끄기 버튼의 메시지명은 "led_off_event"

2. 노드 소켓 서버를 거쳐 MQTT 브로커에 위 이벤트 내용이 전달되도록 하자.

3. 위모스 보드에서 브로커로부터 전달된 토픽을 읽어들이고, 그때그때
LED의 온오프를 제어할 수 있도록 하자.

 

먼저 package.json파일입니다.

{
  "name": "mqtt-server",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "dev": "nodemon app.js"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "nodemon": "^3.0.1"
  },
  "dependencies": {
    "express": "^4.18.2",
    "mqtt": "^5.1.3",
    "socket.io": "^4.7.2"
  }
}

nodemon과 express, mqtt, socket.io 총 4가지 패키지를 사용합니다.

 

다음은 app.js파일입니다.

const mqtt = require("mqtt");
const client = mqtt.connect("IPv4주소");
const express = require("express");
const app = express();
const bodyParser=require("body-parser");
const PORT = process.env.PORT || 3000

// express 기능과 소켓 통신을 제공하는 http 서버 만들기
const http = require("http");
const server = http.createServer(app);
const socket = require("socket.io")
const sio = socket(server) 

app.use(express.static(__dirname + "/public"));
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());

// 커넥트 이벤트 핸들링
// MQTT 연결이 되면, inTopic을 구독할 것이다!
client.on("connect", () => { 
    console.log("mqtt connected");
    client.subscribe("inTopic");
});

// 구독하고 있는 토픽이 왔을 때 이벤트 핸들링
client.on("message", (topic, message) => {
    console.log(topic)
    console.log(String(message))
})

// 소켓 서버에 소켓 클라이언트가 연결되면~
sio.on("connect", (socket) => {
    console.log("socket connected")

    // 소켓 클라이언트에 대한 처리를 이렇게 하겠다~!
    socket.on("led_on_event", (event) => {
        console.log(event)
        client.publish("outTopic", String(event));
    })
    socket.on("led_off_event", (event) => {
        console.log(event)
        client.publish("outTopic", String(event));
    })
})



server.listen(PORT, (err)=>{ 
    if(err){
        return console.log(err);
    }else{
        console.log("SERVER IS LISTENING NOW ON PORT", PORT);
    }
});

다음은 index.html 파일입니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MQTT</title>
</head>
<body>
    <button id="led-on">LED ON</button>
    <button id="led-off">LED OFF</button>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const onBtn = document.getElementById("led-on")
        const offBtn = document.getElementById("led-off")
        socket = io.connect(); // 이 페이지에서 소켓 연결하기
        onBtn.addEventListener("click", function(){
            socket.emit("led_on_event", 1);
        })
        offBtn.addEventListener("click", function(){
            socket.emit("led_off_event", 0);
        })
    </script>
</body>
</html>

예제에서 제시한 조건에 맞게 led-on버튼과 led-off버튼 두개를 만들어 줬구요.

켜기 버튼(1)의 메시지 명은 led_on_event,

끄기 버튼(0)의 메시지 명은 led_off_event로 구성하였습니다.

 

마지막으로 아두이노 스케치 파일입니다.

// 아두이노에서 MQTT 통신으로 LED 제어 및 버튼 눌러 전송하기 

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define LED_PIN D10

const char *ssid = "WIFI아이디";
const char *password = "WIFI비번";
const char *mqtt_server = "IPv4주소";

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");

  String strData = "";
  for (int i = 0; i < length; i++) {
    strData += (char)payload[i];
  }
  
  Serial.println(strData);
  if (strData.toInt())  digitalWrite(LED_PIN, HIGH);
  else digitalWrite(LED_PIN, LOW);
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("arduinoClient")) {
      Serial.println("connected");
      client.subscribe("outTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(9600);
  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());
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  pinMode(LED_PIN,OUTPUT);
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

코드를 실행하면

 

위와같이 localhost:3000 페이지에 LED ON버튼과 LED OFF버튼이 생성되고 각각 클릭 시 WeMos보드에 연결된 LED를 제어 할 수 있습니다.