Thanapon Tapala

Backend Developer

Embedded Developer

Smart Farmer

Maker

Thanapon Tapala

Backend Developer

Embedded Developer

Smart Farmer

Maker

Blog Post

[MQTT] ทดลองใช้ MQTT เพื่อควบคุม Sonoff ด้วย NodeJS ครับ

September 12, 2020 MQTT, NodeJs, SONOFF
[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] ลอง MQTT บน NodeJS เถอะครับ

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

 Image for post

ขั้นตอนต่อไปเริ่มพัฒนา 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 ของเราแล้ว

Image for post

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 เพื่อดูผลลัพธ์

Image for post

จริงๆแล้ว Tasmota firmware มีของดีอีกเยอะเลยครับไม่ว่าจะเป็นข้อมูลที่ response มาจากตัว firmware แล้วผ่าน MQTT ซึ่งเราสามารถนำข้อมูลต่างๆนั้นมาทำเป็น Dashboard หรือแสดงสถานะต่างๆได้เป็นอย่างดีเลยครับ ไม่ว่าอยากจะทำ Smarthome เอย หรือ Smart ต่างๆ Tasmota และ Sonoff นี้น่าจะช่วยในส่วนของ hardware สำหรับนักพัฒนาได้เยอะครับ หากมีข้อผิดพลาดประการใด กราบขออภัยด้วยครับ 🙂

สำหรับวันนี้ขอบคุณและสวัสดีครับ

  • Github code example

toygame/nodejs-tasmota

https://github.com/toygame/nodejs-tasmota
Taggs: