2024年5月22日 星期三

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

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














ESP32 arduino程式 (WOKWI)

// Wifi 與 MQttClient 程式庫
#include <ArduinoMqttClient.h>
#include <WiFi.h>
     
int LED = 2;  //定義LED接腳

char ssid[]="Wokwi-GUEST";
char pass[]="";

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

//const char broker[] = "test.mosquitto.org";
const char broker[] = "broker.mqtt-dashboard.com";
int        port     = 1883;
String json = "";

const char *SubTopic1 = "alex9ufo/led/led_event";
const char *PubTopic2 = "alex9ufo/led/led_status";

const char willTopic[] = "alex9ufo/led/Starting";
//===========================================================
//布林代數 LED狀態 是否連上網路ESP32 ready ?
bool ledState = false;
bool atwork = false;
bool Send = false;  //true
String LEDjson = "";
int Count= 0;
bool Flash = false;  //true
bool Timer = false;  //true

//===========================================================
void onMqttMessage(int messageSize) {
  // we received a message, print out the topic and contents
  Serial.print("Received a message with topic '");
  Serial.print(mqttClient.messageTopic());
  String Topic= mqttClient.messageTopic();
  Serial.print("', duplicate = ");
  Serial.print(mqttClient.messageDup() ? "true" : "false");
  Serial.print(", QoS = ");
  Serial.print(mqttClient.messageQoS());
  Serial.print(", retained = ");
  Serial.print(mqttClient.messageRetain() ? "true" : "false");
  Serial.print("', length ");
  Serial.print(messageSize);
  Serial.println(" bytes:");
  String message="";
  // use the Stream interface to print the contents
  while (mqttClient.available()) {
    //Serial.print((char)mqttClient.read());
    message += (char)mqttClient.read();
  }

  Serial.println(message);
  message.trim();
  Topic.trim();

  if (Topic=="alex9ufo/led/led_event") {
  if (message == "on") {
    digitalWrite(LED, LOW);  // Turn on the LED
    //ledState = true;  //ledState = ture HIGH
    //設定 各個 旗號
    LEDjson ="ON";
    Send = true ;
    Serial.print("LED =");
    Serial.println(LEDjson);
  }

  if (message == "off" ) {
    digitalWrite(LED, HIGH); // Turn off the LED
    //ledState = false; //ledState = false LOW
    LEDjson ="OFF";
    Send = true ;
    Serial.print("LED =");
    Serial.println(LEDjson);
  }
 
  if (message == "flash" ) {
    digitalWrite(LED, HIGH); // Turn off the LED
    Flash = true;
    Timer = false;
    LEDjson ="FLASH";
    Send = true ;  
    Serial.print("LED =");
    Serial.println(LEDjson);      
  }

  if (message == "timer" ) {
    digitalWrite(LED, LOW); // Turn off the LED
    Flash = false;
    Timer = true;
    LEDjson ="TIMER";
    Send = true ;
    Count= 11;
    Serial.print("LED =");
    Serial.println(LEDjson);  
  }
 
    Serial.println();
    Serial.println("-----------------------");
  }  

}

//===========================================================
//副程式  setup wifi
void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);     //print ssid
  WiFi.begin(ssid, pass);  //初始化WiFi 函式庫並回傳目前的網路狀態
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }   //假設 wifi 未連接 show ………

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}  
//===========================================================
//判斷 旗號Flash , Timer 是否為真
void LED_Message() {
  //判斷 旗號 Flash / timer  是否為真 ? 閃爍 定時
 
  if (Flash){
    digitalWrite(LED, !digitalRead(LED));
    delay(500);
    if (digitalRead(LED))
      ledState = true;
    else
      ledState = false;

  } //(Flash)

  if (Timer) {
    digitalWrite(LED, LOW);
    delay(500);
    if (digitalRead(LED))
      ledState = true;
    else
      ledState = false;

  Count=Count-1;
  if (Count == 0 ){
    Timer=false;
    digitalWrite(LED, HIGH);
    ledState = false;
    }
  } //(Timer)
 
 
  ////判斷 旗號 Send 是否為真 回傳MQTT訊息到MQTT Broker 
  if (Send) {
    // Convert JSON string to character array
    Serial.print("Publish message: ");
    Serial.println(LEDjson);
    LEDjson.trim();

    bool retained = false;
    int qos = 1;
    bool dup = false;
   
    // Publish JSON character array to MQTT topic
    mqttClient.beginMessage(PubTopic2,  LEDjson.length(), retained, qos, dup);  //LED Status
    mqttClient.print(LEDjson);
    mqttClient.endMessage();
    Send = false;    //處理過後 旗號 Send為假
  }

}
//===========================================================
void setup() {
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);  // Turn off the LED initially
  //Initialize serial and wait for port to open:
  Serial.begin(115200);   // Initialize serial communications with the PC
  while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
 
  setup_wifi();
  Serial.println("You're connected to the network");
  Serial.println();
 
  String willPayload = "ESP32 Start working....!";
  bool willRetain = true;
  int willQos = 1;

  mqttClient.beginWill(willTopic, willPayload.length(), willRetain, willQos);
  mqttClient.print(willPayload);
  mqttClient.endWill();

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }

  Serial.println("You're connected to the MQTT broker!");
  Serial.println();

  // set the message receive callback
  mqttClient.onMessage(onMqttMessage);
  Serial.print("Subscribing to topic: ");
  Serial.println(SubTopic1);
  // subscribe to a topic
  // the second parameter sets the QoS of the subscription,
  // the the library supports subscribing at QoS 0, 1, or 2
  int subscribeQos = 1;
  mqttClient.subscribe(SubTopic1, subscribeQos);

}
//===========================================================
void loop() {
 
  // call poll() regularly to allow the library to receive MQTT messages and
  // send MQTT keep alives which avoids being disconnected by the broker
  mqttClient.poll();
  LED_Message();

}
////===========================================================

Node-Red程式


[{"id":"6db0792d589a26e2","type":"mqtt in","z":"c9d071441c94c0e7","name":"","topic":"alex9ufo/led/led_status","qos":"1","datatype":"auto","broker":"841df58d.ee5e98","nl":false,"rap":false,"inputs":0,"x":200,"y":120,"wires":[["a1cd3276635a9a62","738716cf2f80f8f7","64502c34c702da2c"]]},{"id":"a93f7ceda0044d1f","type":"ui_text","z":"c9d071441c94c0e7","group":"2025d633009cdf6e","order":1,"width":0,"height":0,"name":"","label":"ESP32發行到MQTT的資料","format":"{{msg.payload}}","layout":"col-center","className":"","x":600,"y":160,"wires":[]},{"id":"a4c4e644a52c93aa","type":"ui_button","z":"c9d071441c94c0e7","name":"","group":"2025d633009cdf6e","order":2,"width":3,"height":1,"passthru":false,"label":"LED 開","tooltip":"","color":"white","bgcolor":"","className":"","icon":"fa-circle","payload":"on","payloadType":"str","topic":"","topicType":"str","x":160,"y":480,"wires":[["23945966b4a86a62","43535048f522eeba","0e871c9b208638f4"]]},{"id":"2a584c35ac3d4198","type":"ui_button","z":"c9d071441c94c0e7","name":"","group":"2025d633009cdf6e","order":3,"width":3,"height":1,"passthru":false,"label":"LED 關","tooltip":"","color":"black","bgcolor":"","className":"","icon":"fa-circle-o","payload":"off","payloadType":"str","topic":"","topicType":"str","x":160,"y":520,"wires":[["23945966b4a86a62","43535048f522eeba","0e871c9b208638f4"]]},{"id":"23945966b4a86a62","type":"mqtt out","z":"c9d071441c94c0e7","name":"","topic":"alex9ufo/led/led_event","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"841df58d.ee5e98","x":440,"y":540,"wires":[]},{"id":"a1cd3276635a9a62","type":"function","z":"c9d071441c94c0e7","name":"Format timestamp","func":"var date = new Date();\nvar h = date.getHours()+8;\nvar m = date.getMinutes();\nvar s = date.getSeconds();\nif(h<10){\n    h = '0'+h;\n}\nif(m<10){\n    m = '0' + m;\n}\nif(s<10){\n    s = '0' + s;\n}\nmsg.payload = msg.payload + ' --> Time:(' + h + ':' + m + ':' + s + ')' ;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":310,"y":300,"wires":[["ee09d17a600f5750"]]},{"id":"ee09d17a600f5750","type":"function","z":"c9d071441c94c0e7","name":"Set Line API ","func":"msg.headers = {'content-type':'application/x-www-form-urlencoded','Authorization':'Bearer A4wwPNh2WqB7dlfeQyyIAwtggn1kfZSI5LkkCdia1gB'};\nmsg.payload = {\"message\":msg.payload};\nreturn msg;\n\n//oR7KdXvK1eobRr2sRRgsl4PMq23DjDlhfUs96SyUBZu","outputs":1,"noerr":0,"x":490,"y":300,"wires":[["8ae42888b0eda1c3"]]},{"id":"8ae42888b0eda1c3","type":"http request","z":"c9d071441c94c0e7","name":"","method":"POST","ret":"txt","paytoqs":false,"url":"https://notify-api.line.me/api/notify","tls":"","persist":false,"proxy":"","authType":"","x":640,"y":300,"wires":[["db7f3839ab3d8949"]]},{"id":"db7f3839ab3d8949","type":"debug","z":"c9d071441c94c0e7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":790,"y":300,"wires":[]},{"id":"738716cf2f80f8f7","type":"debug","z":"c9d071441c94c0e7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":450,"y":120,"wires":[]},{"id":"e1120ef4f7246745","type":"ui_audio","z":"c9d071441c94c0e7","name":"","group":"2025d633009cdf6e","voice":"Microsoft Hanhan - Chinese (Traditional, Taiwan)","always":true,"x":540,"y":200,"wires":[]},{"id":"64502c34c702da2c","type":"function","z":"c9d071441c94c0e7","name":"","func":"var st1;\nif (msg.payload === \"ON\") {\n   st1=\"LED開\"; \n} \nelse if (msg.payload === \"OFF\") {\n  st1=\"LED關\";\n}\nelse if (msg.payload === \"FLASH\") {\n  st1=\"LED閃爍\";\n}\nelse if (msg.payload === \"TIMER\") {\n  st1=\"LED開五秒鐘\";\n}\nelse if (msg.payload === \"TOGGLE\") {\n  st1=\"LED ON OFF 交換\";\n}\n\nmsg.payload=st1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":200,"wires":[["e1120ef4f7246745","a93f7ceda0044d1f","a786898f9d4ec211"]]},{"id":"66ca15b53c7abef6","type":"ui_button","z":"c9d071441c94c0e7","name":"","group":"2025d633009cdf6e","order":4,"width":3,"height":1,"passthru":false,"label":"LED 開5秒鐘","tooltip":"","color":"purple","bgcolor":"","className":"","icon":"fa-circle-o","payload":"timer","payloadType":"str","topic":"","topicType":"str","x":170,"y":600,"wires":[["23945966b4a86a62","43535048f522eeba","0e871c9b208638f4"]]},{"id":"a786898f9d4ec211","type":"function","z":"c9d071441c94c0e7","name":"INSERT","func":"//msg.topic = \"INSERT INTO LED (time_led, led_status) VALUES (?,?)\";\n\nvar status= msg.payload;\n\nvar Today = new Date();\nvar yyyy = Today.getFullYear(); //年\nvar MM = Today.getMonth()+1;    //月\nvar dd = Today.getDate();       //日\nvar h = Today.getHours();       //時\nvar m = Today.getMinutes();     //分\nvar s = Today.getSeconds();     //秒\n\nif(MM<10)\n{\n   MM = '0'+MM;\n}\n\nif(dd<10)\n{\n   dd = '0'+dd;\n}\n\nif(h<10)\n{\n   h = '0'+h;\n}\n\nif(m<10)\n{\n  m = '0' + m;\n}\n\nif(s<10)\n{\n  s = '0' + s;\n}\n\nvar hms= yyyy + '/'+ MM + '/'+ dd + ' ' + h + ':' + m + ':' + s ;\n// Create a Params variable\n// with a time and value component\n//\nmsg.params = { $thetime: hms, $thestatus:msg.payload }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":240,"wires":[["8bb87a4be04a5509"]]},{"id":"8bb87a4be04a5509","type":"sqlite","z":"c9d071441c94c0e7","mydb":"19f59ce9.3edc23","sqlquery":"prepared","sql":"insert into LED (time_led, led_status) values ($thetime , $thestatus)","name":"LED Status","x":690,"y":240,"wires":[["75a3547496ae3f33","13b3be8f4aa11d89"]]},{"id":"75a3547496ae3f33","type":"debug","z":"c9d071441c94c0e7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":870,"y":240,"wires":[]},{"id":"35ae4925ad06e2a7","type":"comment","z":"c9d071441c94c0e7","name":"Node-Red publish 到 HiveMQ Broker  , ESP32訂閱","info":"將 alex9ufo/inTopic 到(publish)HiveMQ Broker \n給 Arduino 訂閱(Subscribe)","x":290,"y":640,"wires":[]},{"id":"673a65ce219a2776","type":"comment","z":"c9d071441c94c0e7","name":"ESP32向 HiveMQ Broker發行 Node-Red 訂閱subscribe","info":"將  Arduino 發行到(publish)HiveMQ Broker alex9ufo/led/led_status \n給 Node-red 或 MQTTB-Box 訂閱(Subscribe)","x":300,"y":80,"wires":[]},{"id":"46bef94da56e9e35","type":"ui_button","z":"c9d071441c94c0e7","name":"","group":"2025d633009cdf6e","order":5,"width":3,"height":1,"passthru":false,"label":"LED 閃爍","tooltip":"","color":"yellow","bgcolor":"","className":"","icon":"fa-circle-o","payload":"flash","payloadType":"str","topic":"","topicType":"str","x":160,"y":560,"wires":[["23945966b4a86a62","43535048f522eeba","0e871c9b208638f4"]]},{"id":"43535048f522eeba","type":"ui_audio","z":"c9d071441c94c0e7","name":"","group":"2025d633009cdf6e","voice":"Microsoft Hanhan - Chinese (Traditional, Taiwan)","always":true,"x":420,"y":600,"wires":[]},{"id":"0e871c9b208638f4","type":"ui_text","z":"c9d071441c94c0e7","group":"2025d633009cdf6e","order":8,"width":0,"height":0,"name":"","label":"Node-RED發行到MQTT的資料","format":"{{msg.payload}}","layout":"row-center","className":"","x":470,"y":480,"wires":[]},{"id":"8c5d0970feee3d0a","type":"function","z":"c9d071441c94c0e7","name":"產生資料庫TABLE","func":"msg.topic = ' CREATE TABLE \"LED\" (\t\"id\"\tINTEGER,\t\"time_led\"\tTEXT,\"led_status\"\tTEXT,PRIMARY KEY(\"id\" AUTOINCREMENT))';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":400,"wires":[["cb600b16db5ab028"]]},{"id":"ce0b5a66dea91b1c","type":"inject","z":"c9d071441c94c0e7","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":290,"y":380,"wires":[["8c5d0970feee3d0a"]]},{"id":"acd66448686808e1","type":"ui_button","z":"c9d071441c94c0e7","name":"建立LED資料庫(只能執行一次)","group":"2025d633009cdf6e","order":7,"width":6,"height":1,"passthru":false,"label":"建立LED資料庫(只能執行一次)","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"","topicType":"str","x":230,"y":420,"wires":[["8c5d0970feee3d0a"]]},{"id":"cb600b16db5ab028","type":"sqlite","z":"c9d071441c94c0e7","mydb":"19f59ce9.3edc23","sqlquery":"msg.topic","sql":"","name":"LED Status","x":710,"y":400,"wires":[["b24d5177b932f26d","5b354bf0fac7500b"]]},{"id":"b24d5177b932f26d","type":"debug","z":"c9d071441c94c0e7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":870,"y":480,"wires":[]},{"id":"5b354bf0fac7500b","type":"ui_template","z":"c9d071441c94c0e7","group":"2025d633009cdf6e","name":"","order":9,"width":12,"height":5,"format":"<table style=\"width:100%\">\n  <tr>\n    <th>Index</th> \n    <th>       Time</th> \n    <th>Status</th>\n  </tr>\n  <tr ng-repeat=\"x in msg.payload | limitTo:100\">\n    <td>     {{$index}}</td>\n    <td>         {{msg.payload[$index].time_led }}</td>\n    <td>        {{msg.payload[$index].led_status}}</td> \n  </tr>\n</table>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","className":"","x":860,"y":400,"wires":[[]]},{"id":"ea79e094492fca0a","type":"ui_button","z":"c9d071441c94c0e7","name":"","group":"2025d633009cdf6e","order":6,"width":6,"height":1,"passthru":false,"label":"檢視LED資料庫","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"檢視LED資料庫","payloadType":"str","topic":"SELECT * FROM LED ORDER BY  id  DESC LIMIT 100;","topicType":"str","x":500,"y":440,"wires":[["cb600b16db5ab028"]]},{"id":"81806107feb4aff6","type":"mqtt in","z":"c9d071441c94c0e7","name":"","topic":"alex9ufo/led/led_event","qos":"1","datatype":"auto","broker":"841df58d.ee5e98","nl":false,"rap":false,"inputs":0,"x":200,"y":680,"wires":[["b260d4e2a11c596b"]]},{"id":"b260d4e2a11c596b","type":"debug","z":"c9d071441c94c0e7","name":"debug 302","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":430,"y":680,"wires":[]},{"id":"66b239493f69d8ac","type":"comment","z":"c9d071441c94c0e7","name":"Line API","info":"","x":280,"y":260,"wires":[]},{"id":"13b3be8f4aa11d89","type":"function","z":"c9d071441c94c0e7","name":"function View","func":"msg.topic = \"SELECT * FROM LED ORDER BY  id  DESC LIMIT 100\";\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":360,"wires":[["cb600b16db5ab028"]]},{"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":"2025d633009cdf6e","type":"ui_group","name":"LED","tab":"2eed7cc3b24b8f69","order":1,"disp":true,"width":"12","collapse":false,"className":""},{"id":"19f59ce9.3edc23","type":"sqlitedb","db":"C:\\Users\\User\\.node-red\\EX2_1_2024.db","mode":"RWC"},{"id":"2eed7cc3b24b8f69","type":"ui_tab","name":"WOKWI_LED","icon":"dashboard","order":125,"disabled":false,"hidden":false}]








沒有留言:

張貼留言

Messaging API作為替代方案

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