오늘은 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를 제어 할 수 있습니다.