iT邦幫忙

1

前端開發筆記:如何在React專案使用MQTT

Bob 2023-11-08 11:29:42838 瀏覽
  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20231107/20163756rbhQU1MSfu.jpg

最近終於完成公司新產品的前端開發啦!不過在開發時也遇到了不少挑戰,其中最難處理的就屬「MQTT通訊協定」的部分了...😅

而自己在study或是Google資料的過程中,發現「React.js + MQTT」的資訊好像比較少一些,因此也在這邊把自己的處理作法紀錄下來,之後若有更佳的作法也會再更新👍


【什麼是MQTT?】

MQTT是一種輕量級的通訊協定,目前主要在物聯網(IoT)領域中被廣泛使用。而其採用「Publish發佈/Subscribe訂閱」的模式,當發佈者將訊息發佈在一個Topic(主題)後,即透過Broker(訊息代理)轉發,讓所有已訂閱該Topic的訂閱者接收到訊息。

以上關於協定的簡介就先到這邊,更詳細的概念說明可以參考這一篇囉 ↓

https://resource.webduino.io/blog/mqtt-guide

【安裝】

一般情況是直接安裝官方的「MQTT.js」,但在React.js的專案裡使用,可能會產生不少Webpack環境以及執行上的錯誤。不過幸運的是,近期已有熱心人士提供修正完成的版本,因此若想節省時間、直接使用的話,建議可以安裝「precompiled-mqtt」

npm i precompiled-mqtt

也提供MQTT.js官方文件於下方連結,內容中有各API的使用說明:

https://github.com/mqttjs/MQTT.js

【實作】

  • 前置作業

    由於主要為了測試MQTT的收發,就先用幾個簡單元件來建立demo頁面吧:

    import { useEffect, useState } from 'react';
    
    const MqttDemo = () => {
         const [data, setData] = useState(
             {
                 topic: '-',
                 message: '-',
             }
         );
    
         return (
             <div style={{width: '400px', margin: 'auto'}}>
                 <h3>
                   {`topic: ${data.topic}, Message: ${data.message}`}
                 </h3>
                 <button type='button'>
                     {'發佈(Publish)'}
                 </button>
             </div>
         )
    };
    
    export default MqttDemo;
    
    

    Demo頁面 - 示意圖

  • 使用方式

    • 首先將安裝好的「precompiled-mqtt」引入 ▼
    import mqtt from 'precompiled-mqtt';
    
    • 與Broker(訊息代理)建立連線 ▼

    在沒有架設Broker的情況下,可以使用「Eclipse Mosquitto™」所提供的測試Server來實作收發功能https://test.mosquitto.org/ )。

    ★ 不過要注意的是,由於瀏覽器(Browser)環境不支援mqtt通訊協定,因此Web應用程式須透過WebSocket協定來連線。將瀏覽器成為基於WebSocket的MQTT client(MQTT over WebScoket),才能直接接收資料。

    找到Port 8081就是我們需要的「MQTT over WebScoket」後,使用connect API連線、即可取得一個Client EventEmitter(事件發射器)。

    const client = mqtt.connect('https://test.mosquitto.org:8081/');
    
    • 訂閱Topic(主題)與接收訊息 ▼

    取得Client後,就可以透過「subscribe API」與「監聽message事件」,來訂閱指定主題與接收訊息。

    在message事件的callback參數中,「topic」代表這則訊息是由哪個主題發送過來的,而「payload」則是其訊息內容

    而由於payload的資料型態是「Buffer」,所以需要使用toString()將其轉換為字串。

    const subMessage = (client) => {
    
         client.subscribe('/test1103');
    
         client.on('message', (topic, payload) => {
             const data2String = payload.toString();
             setData(
                 {
                     topic: topic, 
                     message: JSON.parse(data2String)
                 }
             );    
         });
    };
    

    最後將上方寫好function傳入useEffect。讓React在render完成後,直接開始訂閱與接收訊息,並在元件卸載時與Broker結束連線(若沒有結束連線,即便切換路徑也會持續收到訊息)

    e.g. 現在當有人把”Hello”訊息發佈到「test1103」這個主題,這邊的message事件就會觸發、並接收到”Hello”。

    基本的MQTT連線/訂閱/接收,在這個階段就算是實作完成了。不過若沒有訊息發佈的話,其實也不易確認是否有正常運作吧~接著就直接實作一個發佈(Publish)功能來驗證看看囉

    useEffect(()=>{
         subMessage(client);
         return () => {
             client.end();
         };
    },[])
    
    • 發佈Topic(主題)與訊息 ▼

    我們將發佈功能寫成function,並綁定在按鈕的onClick事件裡,每次點擊就發佈一則訊息出去。

    發佈的topic就是我們已訂閱好的「test1103」、message內容則設定為發佈當下的時戳,以便於確認每次發佈的訊息是否皆有收到。

    ★ message的資料型態必須是「字串」、「Buffer」或「ArrayBuffer」,因此將時戳轉換為字串後再發佈。

    const pubMessage = (client) => {
         const getTimestamp = new Date().getTime();
         client.publish('/test1103', `${getTimestamp}`);
    };
    
    <button 
         type='button'
         onClick={()=>{pubMessage(client)}}
         >
         {'發佈(Publish)'}
    </button>
    

    最後就可以來實際點擊測試啦!從下圖可以看到,我們每次發佈與接收到的「主題+訊息」

    Demo頁面 - 示意圖

  • 附上完整程式碼

import mqtt from 'precompiled-mqtt';
import { useEffect, useState } from 'react';

const MqttDemo = () => {
    const client = mqtt.connect('https://test.mosquitto.org:8081/');
    const [data, setData] = useState(
        {
            topic: '-',
            message: '-',
        }
    );

    const subMessage = (client) => {
        client.subscribe('/test1103');
        client.on('message', (topic, payload) => {
            const data2String = payload.toString();
            setData(
                {
                    topic: topic, 
                    message: JSON.parse(data2String)
                }
            );    
        });
    };

    const pubMessage = (client) => {
        const getTimestamp = new Date().getTime();
        client.publish('/test1103', `${getTimestamp}`);
    };

    useEffect(()=>{
        subMessage(client);
        return () => {
            client.end();
        };
    },[])

    return (
        <div style={{width: '400px', margin: 'auto'}}>
            <h3>
                {`topic: ${data.topic}, Message: ${data.message}`}
            </h3>
            <button 
                type='button'
                onClick={()=>{pubMessage(client)}}
                >
                {'發佈(Publish)'}
            </button>
        </div>
    )
};

export default MqttDemo;

以上React+MQTT的基本使用差不多就到這邊啦~
不過之前開發過程中,最頭痛的是在搭配Highcharts作時數圖的部分,後續再把相關過程整理上來囉!


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言