2024年5月18日 星期六

ESP32 — MQTT 基本範例 (Node-Red)

  ESP32 — MQTT 基本範例

介紹

本課程將展示WOKWI ESP32 模擬的基本MQTT協定使用



  • 每兩秒向主題“alex9ufo/outTopic”發布“hello world”。
  • 訂閱主題“alex9ufo/inTopic”,列印收到的所有訊息。
  • 它假設接收到的有效負載是字串而不是二進位。
  • 如果訂閱的訊息為“ON”,則點亮板載LED。
  • 如果訂閱的訊息為“OFF”,則熄滅板載LED。

準備:

  • https://wokwi.com/projects/new/esp32 。 wokwi 註冊


  •  Node-RED 安裝
  • Windows 作業系統  源自於https://cumi.co/20221213/

    1. 安裝Node.js主程式,下載安裝檔案,執行安裝。

    2. 安裝完成之後開啟CMD,確認node及npm版本。

    3. CMD輸入 npm install -g --unsafe-perm node-red 安裝Node-RED。

    4. CMD輸入node-red啟動Node-RED。

    5. 瀏覽器開啟網址http://127.0.0.1:1880

    6. 找到Node-Red設定目錄。

    7. CMD輸入 node-red admin hash-pw,使用工具產生密碼加密。

    8. 開啟Node-Red設定檔,adminAuth把註解移除,把加密的密碼貼上去。

    9. 重新啟用node-red,瀏覽器打開node-red輸入設定之帳號密碼,即可登入。


  • [Node-RED] dashboard儀表板   

    node-red-dashboard



  • http://blog.3dgowl.com/node-red-dashboard%E5%84%80%E8%A1%A8%E6%9D%BF/
  • node-red-node-sqlite

  •   
    • 安裝sqlite節點

因為 Node-RED 中預設未安裝它。

從主選單中,選擇  選單->節點管理  (menu->manage palette),然後使用節點管理配置框,選擇「安裝」標籤。在搜尋欄位中輸入 sqlite,您將看到類似於下面螢幕截圖的結果。

選擇node-red-node-sqlite並選擇安裝。




































WOKWI設定:
  • sketch.ion程式。
#include <WiFi.h>
#include "PubSubClient.h"
// WiFi
char ssid[]="Wokwi-GUEST";
char pass[]="";
// MQTT Broker
const char *mqtt_broker = "broker.mqtt-dashboard.com";//"broker.emqx.io";//Public Broker
const char *mqtt_username = "hivemqtt";
const char *mqtt_password = "public";
const int mqtt_port = 1883;
// App Protcol ---> Port
const char *topic_publish = "alex9ufo/outTopic";//Topic ESP32 Pusblish
const char *topic_subsrcibe = "alex9ufo/inTopic";//Topic ESp32 Subscribe

WiFiClient hamada;//WIFI Opject
PubSubClient client(hamada);//OOP

void callback(char *topic, byte *payload, unsigned int length);
#define LED 2
bool ledState=false;
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;


void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(topic_publish, "Hello world.....");
      client.subscribe(topic_subsrcibe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup(){
   // Setting LED pin as output
    pinMode(LED, OUTPUT);
    digitalWrite(LED, LOW);  // Turn off the LED initially
    //Open a serial connection to display program results and establish a connection to the Wi-Fi network.
    // Set software serial baud to 115200;
    Serial.begin(115200);
    // Connecting to a Wi-Fi network
    WiFi.begin(ssid, pass);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("Connecting to WiFi..");
    }
        Serial.println("Connected to the Wi-Fi network");
    // Utilize PubSubClient to establish a connection with the MQTT broker.
    //connecting to a mqtt broker
    Serial.println("Before Connect MQTT");
    //Broker Configuration
    client.setServer(mqtt_broker, mqtt_port);
   
   while (!client.connected()) {
        String client_id = "esp32-client-";
        client_id =client_id+ String(WiFi.macAddress());
        //consloe.log("x"+"y");//xy

        //ESP32-ID -----> esp32-client-macaddress
        //variable.c_str()--->char [] , String
        Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str());
        if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            Serial.println("Public MQTT broker connected");
        } else {
            Serial.print("failed with state ");
            Serial.print(client.state());//1 , 2 , 5
            delay(2000);
        }
    }
    Serial.println("After Connect MQTT");
    client.publish(topic_publish, "Hello world.....");
    client.subscribe(topic_subsrcibe);
    client.setCallback(callback);
}

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

  unsigned long now = millis();
  if (now - lastMsg > 10000) {
    lastMsg = now;
    ++value;
    snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish(topic_publish, msg);
  }
}



void callback(char* topic, byte* message, unsigned int length) {
  printPayload(topic, message, length);  
}

void printPayload(char* topic, byte* message, unsigned int length) {
  // Printing Received Message
  Serial.print("Message received on topic: ");
  Serial.println(topic);

  String messageTemp;
  for(int i=0; i<length; i+=1) {
    messageTemp += (char)message[i];
  }
  if(String(topic) == "alex9ufo/inTopic"){
      Serial.println("alex9ufo/inTopic");
      if(messageTemp=="ON"){
        Serial.println("Led ON");
        digitalWrite(LED,HIGH);
      }
      if(messageTemp=="OFF"){
        Serial.println("Led OFF");
        digitalWrite(LED,LOW);
      }
  }
  Serial.println(messageTemp);
}




  • diagram.json程式 (電路圖)。
{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-esp32-devkit-v1", "id": "esp", "top": -321.7, "left": -168.2, "attrs": {} },
    {
      "type": "wokwi-resistor",
      "id": "r1",
      "top": -225.6,
      "left": 37.85,
      "rotate": 90,
      "attrs": { "value": "1000" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -310.8,
      "left": 32.6,
      "attrs": { "color": "red" }
    }
  ],
  "connections": [
    [ "esp:TX0", "$serialMonitor:RX", "", [] ],
    [ "esp:RX0", "$serialMonitor:TX", "", [] ],
    [ "led1:C", "esp:GND.1", "black", [ "v0" ] ],
    [ "r1:1", "led1:A", "red", [ "h0" ] ],
    [ "esp:D2", "r1:2", "red", [ "h0" ] ]
  ],
  "dependencies": {}
}




  • Library manager --> Project Libaries --> Installed Libraries  




Node-Red設定:

broker.mqtt-dashboard.com:1883/ws

一、安裝/刪除節點
二、匯入/匯出流程
一、安裝/刪除節點
1.點選右上角的三條橫線下拉選單→「節點管理」(圖1)
2.進入後可以看到已安裝的節點,在此可以禁用或刪除(圖2)
3.被刪除的節點可以再次重新安裝
4.切換至安裝頁面,上方可輸入關鍵字搜尋(圖3)
5.選取要得節點後按下右下角安裝即會進入安裝狀態
特別提醒:安裝和刪除時請確保Node-RED正確運作,切勿關閉或斷線,會造成系統異常而無法開啟和編輯
6.新增的節點將會出現於主畫面左側的節點區
二、匯入/匯出流程
1.點選右上角的三條橫線下拉選單→「匯入、匯出」(圖4)
(1)匯入:將外部檔案放入自己的Node-RED中編輯使用
(2)匯出:將自己的專案轉成jason或文字碼供他人使用
2.點選「匯入」→「匯入所選檔案」→「匯入」(圖5)
特別提醒:若匯入他人資料時本身沒有資料中的結點,Node-RED會無法辨識而跳出警示,需要針對該節點去新增安裝後重新匯入一次,始得正常使用
3.點選「匯出」→「現在的節點」→「下載」(圖6)
(1)按下下載後會匯出jason檔案,需要時再使用匯入功能即可取回資料至Node-RED中
(2)下載旁的「匯出到剪貼簿」會生成文字碼(記事本可開啟),兩種都可以作為匯出的方式
(3)建議當專案完成後即可匯出檔案作為備份以免遺失



  • node-red 






  • node-red 程式  。
[{"id":"5615c3139a44b5d0","type":"mqtt in","z":"01fd8e367f0ac467","name":"WOKWI--out","topic":"alex9ufo/outTopic","qos":"1","datatype":"auto-detect","broker":"841df58d.ee5e98","nl":false,"rap":true,"rh":0,"inputs":0,"x":370,"y":380,"wires":[["74d697432438f140","80fd252ac8b67c26"]]},{"id":"653778e8f0c52bd5","type":"ui_button","z":"01fd8e367f0ac467","name":"","group":"f652932debd19205","order":3,"width":3,"height":1,"passthru":false,"label":"ON","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"ON","payloadType":"str","topic":"topic","topicType":"msg","x":350,"y":200,"wires":[["8f57776b7e4e3094","32f91ec99294708e","74d697432438f140"]]},{"id":"56b07a7f5b5be766","type":"ui_button","z":"01fd8e367f0ac467","name":"","group":"f652932debd19205","order":5,"width":3,"height":1,"passthru":false,"label":"OFF","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"OFF","payloadType":"str","topic":"topic","topicType":"msg","x":350,"y":280,"wires":[["8f57776b7e4e3094","f6e2801b5c496dcb","74d697432438f140"]]},{"id":"80fd252ac8b67c26","type":"ui_text","z":"01fd8e367f0ac467","group":"f652932debd19205","order":9,"width":0,"height":0,"name":"","label":"向WOKWI訂閱的主題 : alex9ufo/outTopic","format":"{{msg.payload}}","layout":"row-left","className":"","x":660,"y":360,"wires":[]},{"id":"74d697432438f140","type":"ui_audio","z":"01fd8e367f0ac467","name":"","group":"f652932debd19205","voice":"Microsoft Yating - Chinese (Traditional, Taiwan)","always":"","x":560,"y":400,"wires":[]},{"id":"8f57776b7e4e3094","type":"mqtt out","z":"01fd8e367f0ac467","name":"ON/OFF","topic":"alex9ufo/inTopic","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"841df58d.ee5e98","x":560,"y":240,"wires":[]},{"id":"00cf1c6bb0742364","type":"ui_led","z":"01fd8e367f0ac467","order":6,"group":"f652932debd19205","width":"5","height":"4","label":"","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"#ff0000","value":"false","valueType":"bool"},{"color":"#008000","value":"true","valueType":"bool"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":true,"name":"","x":770,"y":160,"wires":[]},{"id":"3e44e13a2dbdc6ca","type":"inject","z":"01fd8e367f0ac467","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":550,"y":100,"wires":[["00cf1c6bb0742364"]]},{"id":"c97bf463532d9220","type":"inject","z":"01fd8e367f0ac467","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"false","payloadType":"bool","x":550,"y":140,"wires":[["00cf1c6bb0742364"]]},{"id":"32f91ec99294708e","type":"function","z":"01fd8e367f0ac467","name":"function ON","func":"var test=msg.payload;\n\nif (test==\"ON\")\n msg.payload=true;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":200,"wires":[["00cf1c6bb0742364","f59989c133de1fcd"]]},{"id":"f6e2801b5c496dcb","type":"function","z":"01fd8e367f0ac467","name":"function OFF","func":"var test=msg.payload\nif (test==\"OFF\")\n msg.payload=false;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":280,"wires":[["00cf1c6bb0742364","f59989c133de1fcd"]]},{"id":"f59989c133de1fcd","type":"debug","z":"01fd8e367f0ac467","name":"debug 301","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":790,"y":260,"wires":[]},{"id":"841df58d.ee5e98","type":"mqtt-broker","name":"","broker":"broker.mqtt-dashboard.com","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"15","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"f652932debd19205","type":"ui_group","name":"LED_WOKWI","tab":"b83c5c221c74411b","order":4,"disp":true,"width":"6","collapse":false,"className":""},{"id":"b83c5c221c74411b","type":"ui_tab","name":"Wokwi","icon":"dashboard","order":121,"disabled":false,"hidden":false}]



















沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...