[MQTT] ทดลองใช้ MQTT เพื่อควบคุม Sonoff ด้วย NodeJS ครับ
สืบเนื่องจากบทความคราวก่อนนะครับที่ผมได้เขียนเกี่ยวกับการอัพโหลด TASMOTA firmware สำหรับ Sonoff กันและอีกบทความที่เกี่ยวกับการติดตั้งและใช้งาน MQTT ร่วมกับ NodeJS
สำหรับบทความนี้จะเป็นการรวมทั้งสองบทความก่อนหน้านี้ให้เป็น Web Application สำหรับควบคุม Sonoff โดยผ่าน MQTT Protocol กันนะครับอาจจะออกแนวไปสาย developer นิดนึ่ง แต่ผมจะพยายามเขียนให้ทุกท่านเข้าใจมากที่สุดครับ สำหรับผู้ที่สนใจสามารถดาวน์โหลด code ได้ที่ github ได้นะครับ…
[ESP8266-Sonoff] มาลอง TASMOTA firmware สำหรับ Sonoff กันครับ
สวัสดีครับหลังจากที่หายไปหลายเดือน
พอดีได้มีโอกาสไปลองเล่น Sonoff มา ซึ่งรุ่นที่ได้ลองจะเป็น Module Sonoff Basic ลักษณะจะคล้ายๆกับบัลลาสต์เลยครับแต่ขนาดตัวจะเล็กกว่าประมาณครึ่งเลยที่เดียวครับ
MQTT (Message Queueing Telemetry Transport protocol)คือโปรโตคอลที่ใช้สำหรับสื่อสารกันระหว่าง m2m หรือ machine to machine
เริ่มต้นสร้าง express-generator สำหรับเป็นโครงให้ตัวโปรเจคของเรา
ก่อนจะนำ MQTT มาใช้เราต้องทำการสร้าง web application มาก่อนนะครับ ในที่นี้ผมจะใช้ตัว express-generator และในการสร้าง application ขึ้นมาโดยที่ view engine ผมจะใช้ EJS นะครับซึ่ง syntax จะคล้ายๆกับ html มากๆครับ
$ express --view=ejs nodejs-tasmota
หลังจากนั้นเราก็จะได้โฟลเดอร์ nodejs-tasmota มา โดยภายในโฟลเดอร์นี้ก็จะประกอบไปด้วย
├── app.js ├── bin │ └── www ├── package.json ├── public │ ├── images │ ├── javascripts │ └── stylesheets │ └── style.css ├── routes │ ├── index.js │ └── users.js └── views ├── error.ejs ├── index.ejs
เสร็จแล้วทำการทดสอบการทำงานของ web application ของเราโดยการรัน npm install ก่อนโดยจะเป็นการติดตั้ง package ต่างๆที่จำเป็นสำหรับ application ของเราแล้วทำการรัน npm start ตามลำดับ
$ npm install // Install package dependencies $ npm start // Start service
มาที่ Web browser ของเราไม่ว่าจะเป็น Google chrome หรือ Microsoft Edge ทำการพิมพ์ไปที่ช่อง address : http://localhost:3000 เป็นอันว่าจบการติดตั้งโครงสร้าง web application ที่จะใช้เขียนเชื่อมต่อ MQTT และ Tasmota
ขั้นตอนต่อไปเริ่มพัฒนา nodejs-mqtt กันเลย
ทำการติดตั้ง package MQTT สำหรับ web application ของเราโดยที่พิมพ์คำสั่ง
$ npm install mqtt
หลังจากนั้นเปิดไฟล์ app.js ขึ้นมาเพื่อที่จะแก้ไขตัว application ของเราให้เชื่อมต่อกับ mqtt ได้
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
//------------MQTT section------------//
const mqtt = require('mqtt') // import mqtt connect
// mqtt configuration
const mqttConfig = {
host: 'localhost',
port: 1883,
username: '',
password: ''
}
const client = mqtt.connect(mqttConfig) // create connection to mqtt broker
client.on('connect', function () {
client.subscribe('tasmota/#', function (err) {
if (!err) {
client.publish('tasmota', 'Hello from application mqtt')
}
})
})
client.on('message', function (topic, message) {
// message is Buffer
console.log(message.toString())
})
//------------------------------------//
const indexRouter = require('./routes/index');
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Route endpoint
indexRouter(app,client)
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
ในที่นี้ผมจะกำหนด topic สำหรับ subscribe เป็น “tasmota/#” นะครับ
# แปลว่ายอมรับทุกๆ topic ที่ขึ้นต้นด้วย prefix “tasmota”
เสร็จแล้วหลังจากนั้นทำการแก้ไขไฟล์ views/index.ejs โดยที่ผมจะทำการเพิ่มปุ่มสำหรับเปิดและปิดเจ้าตัว Sonoff นะครับ ซึ่งในไฟล์ views/index.ejs เราก็จะทำการเพิ่ม html button tag กัน
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel="stylesheet" href="/stylesheets/style.css" />
</head>
<body>
<h1><%= title %></h1>
<p>Welcome nodejs-tasmota</p>
<button id="butt_on">เปิด</button>
<button id="butt_off">ปิด</button>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$("#butt_on").click(function (event) {
event.preventDefault();
$.get("/control/on", function (data, status) {
alert("Data: " + data + "\nStatus: " + status);
});
});
$("#butt_off").click(function (event) {
event.preventDefault();
$.get("/control/off", function (data, status) {
alert("Data: " + data + "\nStatus: " + status);
});
});
</script>
</html>
จากโค๊ดจะเห็นว่าผมได้สร้าง button tag เอาไว้สำหรับกด เปิด และ ปิด หลังจากที่ผู้ใช้งานทำการกดแล้วจะเกิด event การ click แล้ว จะไปเรียก Endpoint URL /control/on และ /control/off ผ่าน method GET กันครับ
เป็นอันว่าขั้นตอนที่ 2 ก็เสร็จไปแล้วขั้นตอนที่ 3 กันต่อครับโดยขั้นตอนนี้จะเป็นการเขียนให้ไปเรียก MQTT publish ข้อมูลตามโครงสร้าง MQTT ฝั่งของ Tasmota กัน
ทำการแก้ไขโค๊ดในส่วนของการ route โดยการเปิดไฟล์ route/index.js เพื่อเพิ่ม Endpoint สำหรับการเปิดและปิด Sonoff ซึ่งในส่วนนี้เราจะต้องกำหนดข้อมูล publish ให้เป็นไปตามโครงสร้างของ Tasmota ด้วยนะครับ
const main = (app, client) => {
/* GET home page. */
app.get('/', function (req, res) {
res.render('index', {
title: 'nodejs-tasmota'
});
});
app.get('/control/on', function (req, res) {
const fullTopic = `tasmota/cmnd/tasmota-1/POWER`
client.publish(fullTopic, "ON");
res.send('Turn on!')
})
app.get('/control/off', function (req, res) {
const fullTopic = `tasmota/cmnd/tasmota-1/POWER`
client.publish(fullTopic, "OFF");
res.send('Turn off!')
})
}
module.exports = main;
ภายใน Configuration ของ Sonoff เราจะต้องตั้งค่า Topic และ Full Topic ในการ subscribe
- Topic: tasmota-1
- Full Topic: tasmota/%prefix%/%topic%/
หลังจากนั้นทำการกด Save แล้ว Sonoff ของเราจะทำการ restart ตัวเอง เป็นอันว่าตอนนี้เจ้า Sonoff ของเราพร้อมกับการเชื่อมต่อเข้ากับ web application ของเราแล้ว
Fulltopic : tasmota/${prefix}/${topic}/
- tasmota เป็นชื่อกรุ๊ปของเราสามารถตั้งเป็นชื่ออะไรก็ได้
- prefix คือส่วนที่กำหนดว่าเป็นคำสั่งอะไร เช่น cmnd, stat, tele
- topic คือส่วนที่เรากำหนดได้โดยอาจจะเป็นชื่อของอุปกรณ์ที่สามารถแสดงความเจาะจงถึงอุปกรณ์นั้นๆได้เช่น device_1, device_2
ในการ publish ไปยัง MQTT broker นั้นเราจะต้องสร้าง topic ใน application ของเราให้อยู่ในรูปแบบ Fulltopic ของ Tasmota ซึ่งถ้าเราจะทำการกำหนดสถานะเช่นเปิด/ปิด Sonoff จำเป็นต้องเพิ่มคำสั่งย่อยของ prefix นั้นๆคือ POWER
ทำการรัน application ของเราโดยใช้คำสั่ง
$ npm start
หลังจากนั้นเปิด web browser ของเราไปที่ http://localhost:3000 เพื่อดูผลลัพธ์
จริงๆแล้ว Tasmota firmware มีของดีอีกเยอะเลยครับไม่ว่าจะเป็นข้อมูลที่ response มาจากตัว firmware แล้วผ่าน MQTT ซึ่งเราสามารถนำข้อมูลต่างๆนั้นมาทำเป็น Dashboard หรือแสดงสถานะต่างๆได้เป็นอย่างดีเลยครับ ไม่ว่าอยากจะทำ Smarthome เอย หรือ Smart ต่างๆ Tasmota และ Sonoff นี้น่าจะช่วยในส่วนของ hardware สำหรับนักพัฒนาได้เยอะครับ หากมีข้อผิดพลาดประการใด กราบขออภัยด้วยครับ 🙂
สำหรับวันนี้ขอบคุณและสวัสดีครับ
- Github code example
https://github.com/toygame/nodejs-tasmota