2025年4月29日 星期二

一般天氣預報-今明36小時天氣預報+ Telegram

 一般天氣預報-今明36小時天氣預報+ Telegram 






[{"id":"737e3490ea532e0d","type":"http request","z":"a95bf9b2fb1bf34a","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=rdec-key-123-45678-011121314","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":240,"y":140,"wires":[["5bd9a4a11c02acc0","270b38ecb9506e22"]]},{"id":"f5340d25ef565ed1","type":"function","z":"a95bf9b2fb1bf34a","name":"function ","func":"let tableData = [];\nlet locations = msg.payload.records.location;\n\nlocations.forEach(location => {\n    let locationName = location.locationName;\n    \n    // 取出時間區段\n    location.weatherElement[0].time.forEach((timeEntry, idx) => {\n        tableData.push({\n            city: locationName,\n            startTime: timeEntry.startTime,\n            endTime: timeEntry.endTime,\n            weather: location.weatherElement.find(el => el.elementName === 'Wx').time[idx].parameter.parameterName,\n            maxTemp: location.weatherElement.find(el => el.elementName === 'MaxT').time[idx].parameter.parameterName + \"°C\",\n            minTemp: location.weatherElement.find(el => el.elementName === 'MinT').time[idx].parameter.parameterName + \"°C\",\n            rainProb: location.weatherElement.find(el => el.elementName === 'PoP').time[idx].parameter.parameterName + \"%\"\n        });\n    });\n});\nflow.set(\"weatherData\", tableData)\nmsg.payload = tableData;\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":140,"wires":[["94232e50a9b096f9","9a45d3126da1e62d"]]},{"id":"94232e50a9b096f9","type":"ui_table","z":"a95bf9b2fb1bf34a","group":"91df7aaf835fc89e","name":"","order":5,"width":12,"height":9,"columns":[{"field":"city","title":"城市","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"startTime","title":"開始時間","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"endTime","title":"結束時間","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"weather","title":"天氣","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"maxTemp","title":"最高溫","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"minTemp","title":"最低溫","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"rainProb","title":"降雨機率","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}}],"outputs":0,"cts":false,"x":730,"y":140,"wires":[]},{"id":"9a45d3126da1e62d","type":"debug","z":"a95bf9b2fb1bf34a","name":"debug 352","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":730,"y":180,"wires":[]},{"id":"5bd9a4a11c02acc0","type":"debug","z":"a95bf9b2fb1bf34a","name":"debug 353","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":370,"y":60,"wires":[]},{"id":"270b38ecb9506e22","type":"json","z":"a95bf9b2fb1bf34a","name":"","property":"payload","action":"","pretty":true,"x":370,"y":140,"wires":[["f5340d25ef565ed1","1301871d9b981063","65f8b1f352582e59"]]},{"id":"inject_every_hour","type":"inject","z":"a95bf9b2fb1bf34a","name":"每小時觸發","props":[],"repeat":"3600","crontab":"","once":true,"onceDelay":"1","topic":"","x":90,"y":140,"wires":[["737e3490ea532e0d"]]},{"id":"a2a9c4490849cf8b","type":"ui_dropdown","z":"a95bf9b2fb1bf34a","name":"","label":"","tooltip":"","place":"Select option","group":"91df7aaf835fc89e","order":1,"width":5,"height":1,"passthru":true,"multiple":false,"options":[{"label":"台北市","value":"臺北市","type":"str"},{"label":"新北市","value":"新北市","type":"str"},{"label":"桃園市","value":"桃園市","type":"str"},{"label":"台中市","value":"臺中市","type":"str"},{"label":"台南市","value":"臺南市","type":"str"},{"label":"高雄市","value":"高雄市","type":"str"},{"label":"基隆市","value":"基隆市","type":"str"},{"label":"新竹縣","value":"新竹縣","type":"str"},{"label":"新竹市","value":"新竹市","type":"str"},{"label":"苗栗縣","value":"苗栗縣","type":"str"},{"label":"彰化縣","value":"彰化縣","type":"str"},{"label":"南投縣","value":"南投縣","type":"str"},{"label":"雲林縣","value":"雲林縣","type":"str"},{"label":"嘉義縣","value":"嘉義縣","type":"str"},{"label":"嘉義市","value":"嘉義市","type":"str"},{"label":"屏東縣","value":"屏東縣","type":"str"},{"label":"宜蘭縣","value":"宜蘭縣","type":"str"},{"label":"花蓮縣","value":"花蓮縣","type":"str"},{"label":"臺東縣","value":"臺東縣","type":"str"},{"label":"澎湖縣","value":"澎湖縣","type":"str"},{"label":"金門縣","value":"金門縣","type":"str"},{"label":"連江縣","value":"連江縣","type":"str"}],"payload":"","topic":"topic","topicType":"msg","className":"C:\\Users\\User\\Downloads\\test.css","x":180,"y":320,"wires":[["8636f812551f7b10"]]},{"id":"1301871d9b981063","type":"debug","z":"a95bf9b2fb1bf34a","name":"debug 354","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":550,"y":100,"wires":[]},{"id":"8636f812551f7b10","type":"function","z":"a95bf9b2fb1bf34a","name":"function ","func":"let selectedCity = msg.payload;\nlet allData = flow.get(\"weatherData\") || [];\n\nlet filteredData = allData.filter(item => item.city === selectedCity);\n\nmsg.payload = filteredData;\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":260,"wires":[["9af5d609779771c2","63a8c10c26532ac8","061d5c22afaa4329"]]},{"id":"63a8c10c26532ac8","type":"debug","z":"a95bf9b2fb1bf34a","name":"debug 355","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":530,"y":260,"wires":[]},{"id":"65f8b1f352582e59","type":"function","z":"a95bf9b2fb1bf34a","name":"function  ","func":"msg.payload=msg.payload.records.location;\nvar rawdata =msg.payload;\nvar site_number=rawdata.length;\nvar site_array=[];\nvar i;\n\nfor (i=0; i<site_number;i++)\n{\n    site_array[i]=rawdata[i].locationName;\n}\n\nmsg.payload=site_array;\n \nflow.set(\"weather_sitename\",site_array);\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":180,"y":200,"wires":[["49767f23c0fd65b0"]]},{"id":"49767f23c0fd65b0","type":"change","z":"a95bf9b2fb1bf34a","name":"","rules":[{"t":"set","p":"options","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":200,"wires":[["3c66bb6881bc9762","31d37c65c7878ebf"]]},{"id":"3c66bb6881bc9762","type":"ui_dropdown","z":"a95bf9b2fb1bf34a","name":"","label":"","tooltip":"","place":"Select option","group":"91df7aaf835fc89e","order":3,"width":5,"height":1,"passthru":true,"multiple":false,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"topic","topicType":"msg","className":"","x":180,"y":260,"wires":[["8636f812551f7b10"]]},{"id":"31d37c65c7878ebf","type":"debug","z":"a95bf9b2fb1bf34a","name":"debug 357","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":570,"y":200,"wires":[]},{"id":"9af5d609779771c2","type":"ui_table","z":"a95bf9b2fb1bf34a","group":"91df7aaf835fc89e","name":"","order":4,"width":12,"height":2,"columns":[{"field":"city","title":"城市","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"startTime","title":"開始時間","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"endTime","title":"結束時間","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"weather","title":"天氣","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"maxTemp","title":"最高溫","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"minTemp","title":"最低溫","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"rainProb","title":"降雨機率","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}}],"outputs":0,"cts":false,"x":350,"y":340,"wires":[]},{"id":"f59054d3041da9a3","type":"template","z":"a95bf9b2fb1bf34a","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"選擇到的城市天氣{{payload}}\"}\n","output":"json","x":790,"y":300,"wires":[["700fe53ec9406f9f"]]},{"id":"700fe53ec9406f9f","type":"telegram sender","z":"a95bf9b2fb1bf34a","name":"天氣","bot":"f99c60fa6cddd722","haserroroutput":true,"outputs":2,"x":910,"y":300,"wires":[[],[]]},{"id":"061d5c22afaa4329","type":"function","z":"a95bf9b2fb1bf34a","name":"function  ","func":"let outputStrings = [];\nmsg.payload.forEach(item => {\n    let itemString = \"\";\n    for (const key in item) {\n        if (item.hasOwnProperty(key)) {\n            itemString += key + \": \" + item[key] + \", \";\n        }\n    }\n    // 移除最後多餘的 \", \"\n    itemString = itemString.slice(0, -2);\n    outputStrings.push(itemString);\n});\nmsg.payload = outputStrings;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":300,"wires":[["b390f01b9ea1ba8d","361345cc1e262586","5d6ead30c7620fba"]]},{"id":"b390f01b9ea1ba8d","type":"function","z":"a95bf9b2fb1bf34a","name":"function ","func":"msg.payload=msg.payload[0];\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":300,"wires":[["f59054d3041da9a3"]]},{"id":"361345cc1e262586","type":"function","z":"a95bf9b2fb1bf34a","name":"function ","func":"msg.payload=msg.payload[1];\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":340,"wires":[["0d38a31346a2aa7c"]]},{"id":"5d6ead30c7620fba","type":"function","z":"a95bf9b2fb1bf34a","name":"function ","func":"msg.payload=msg.payload[2];\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":380,"wires":[["d8beaee3b21ee3da"]]},{"id":"0d38a31346a2aa7c","type":"delay","z":"a95bf9b2fb1bf34a","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":740,"y":340,"wires":[["f59054d3041da9a3"]]},{"id":"d8beaee3b21ee3da","type":"delay","z":"a95bf9b2fb1bf34a","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":740,"y":380,"wires":[["f59054d3041da9a3"]]},{"id":"91df7aaf835fc89e","type":"ui_group","name":"Default","tab":"0a96b8dde1b2e50a","order":3,"disp":true,"width":12,"collapse":false,"className":""},{"id":"f99c60fa6cddd722","type":"telegram bot","botname":"ncutedu_weather36_bot","usernames":"","chatids":"","baseapiurl":"","testenvironment":false,"updatemode":"polling","pollinterval":"300","usesocks":false,"sockshost":"","socksprotocol":"socks5","socksport":"6667","socksusername":"anonymous","sockspassword":"","bothost":"","botpath":"","localbothost":"0.0.0.0","localbotport":"8443","publicbotport":"8443","privatekey":"","certificate":"","useselfsignedcertificate":false,"sslterminated":false,"verboselogging":false},{"id":"0a96b8dde1b2e50a","type":"ui_tab","name":"36小時天氣","icon":"dashboard","order":2,"disabled":false,"hidden":false}]

2025年4月27日 星期日

日幣匯率 ( Node-Red 爬蟲 + telegram )

 日幣匯率 ( Node-Red 爬蟲 + telegram )

 由telegram 送出請求 例如 rate,0.23

 到https://rate.bot.com.tw/xrt?Lang=zh-TW

 取得日圓匯率回telegram

 可以 日圓,0.24 或 美元32.5.....取得需要的匯率




Node-Red程式

[{"id":"639381b4.decba","type":"inject","z":"cfd0631de3fd81fd","name":"","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"str"}],"repeat":"3600","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":120,"wires":[["63a4a95.925ad58"]]},{"id":"63a4a95.925ad58","type":"http request","z":"cfd0631de3fd81fd","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://rate.bot.com.tw/xrt?Lang=zh-TW","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":240,"y":120,"wires":[["38a8cc.2269c734"]]},{"id":"38a8cc.2269c734","type":"html","z":"cfd0631de3fd81fd","name":"filter","property":"payload","outproperty":"payload","tag":".rate-content-cash.text-right.print_hide","ret":"html","as":"single","x":370,"y":120,"wires":[["29ecf860.b24508","91e26219.6161e"]]},{"id":"29ecf860.b24508","type":"function","z":"cfd0631de3fd81fd","name":"Get 日圓匯率 1","func":"var currency = 0.20;\n\nvar data = {\n    jpy: Number(msg.payload[15])\n}\n\nvar isLow =  flow.get('isLow') || false;\nmsg.payload = data\nif (data.jpy < currency && !isLow) {\n    isLow = true;\n    flow.set('isLow', isLow);\n    return msg;\n}\nif (data.jpy > currency && !isLow) {\n    isLow = false;\n    flow.set('isLow', isLow);\n    return msg;\n}","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":180,"wires":[["a75c6b33ab13f151"]]},{"id":"1d418e6a.0e52a2","type":"debug","z":"cfd0631de3fd81fd","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":710,"y":100,"wires":[]},{"id":"91e26219.6161e","type":"function","z":"cfd0631de3fd81fd","name":"GET 日圓匯率 2","func":"//var jp = msg.payload[15];\nvar data = {\n    jpy: Number(msg.payload[15])\n}\nvar date = new Date();\nmsg.payload = data\nvar h = date.getHours();\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}\n\n\nvar value = global.get(\"change\")\nif (data.jpy <= value)\n    msg.payload = '(' + h + ':' + m + ':' + s + ')\\n'+\n    '日幣匯率:' + data.jpy ;\nelse\n    msg.payload = '高於設定匯率' +value ;\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":100,"wires":[["1d418e6a.0e52a2","7e4eb32d6c62197b"]]},{"id":"5d6f427ff737f39e","type":"telegram receiver","z":"cfd0631de3fd81fd","name":"牌告匯率","bot":"your_telegram_bot_config_id","saveDataDir":"","filterCommands":false,"x":80,"y":240,"wires":[["ceeeaef0c81e8a5b","bbfe8906520f8a75","5bf1075a988c511d","3d857d7966a8004b"],[]]},{"id":"085d340990cf180b","type":"telegram sender","z":"cfd0631de3fd81fd","name":"牌告匯率","bot":"your_telegram_bot_config_id","haserroroutput":true,"outputs":2,"x":860,"y":180,"wires":[[],[]]},{"id":"a75c6b33ab13f151","type":"debug","z":"cfd0631de3fd81fd","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":650,"y":180,"wires":[]},{"id":"7e4eb32d6c62197b","type":"template","z":"cfd0631de3fd81fd","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"台灣銀行牌告匯率 今日{{payload}}\"}\n","output":"json","x":690,"y":140,"wires":[["085d340990cf180b"]]},{"id":"ceeeaef0c81e8a5b","type":"function","z":"cfd0631de3fd81fd","name":"function ","func":"if (msg.payload.content === 'rate') {\n  return [[{ payload: true }, null]];\n} else {\n  return [[null, { payload: false }]];\n}\n\n","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":260,"wires":[[],["93dd79e280c0f37c"]]},{"id":"bbfe8906520f8a75","type":"switch","z":"cfd0631de3fd81fd","name":"","property":"payload.content","propertyType":"msg","rules":[{"t":"cont","v":"rate","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":230,"y":220,"wires":[["63a4a95.925ad58"],["cc913a5b4576f97b"]]},{"id":"5bf1075a988c511d","type":"function","z":"cfd0631de3fd81fd","name":"function ","func":"const parts = msg.payload.content.split(',');\nconst changeValue = parts[1];\nglobal.set(\"change\", changeValue);\nmsg.payload = [parts[0], changeValue]; // 為了方便後續流程,payload 也包含這兩個值\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":300,"wires":[[]]},{"id":"3d857d7966a8004b","type":"debug","z":"cfd0631de3fd81fd","name":"debug 350","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":250,"y":340,"wires":[]},{"id":"93dd79e280c0f37c","type":"debug","z":"cfd0631de3fd81fd","name":"debug 351","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":510,"y":300,"wires":[]},{"id":"cc913a5b4576f97b","type":"template","z":"cfd0631de3fd81fd","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"輸入資料錯誤\"}\n","output":"json","x":690,"y":240,"wires":[["085d340990cf180b"]]},{"id":"your_telegram_bot_config_id","type":"telegram bot","botname":"@ncutedu_exchange_rate_bot","usernames":"","chatids":"7965218469","baseapiurl":"","testenvironment":false,"pollinterval":"","usesocks":false,"sockshost":"","socksport":"","socksusername":"","sockspassword":"","bothost":"","botpath":"","localbothost":"","localbotport":"","publicbotport":"","privatekey":"","certificate":"","useselfsignedcertificate":false,"sslterminated":false,"verboselogging":false}]

2025年4月26日 星期六

Wokwi ESP32 DHT22 + Telegram + Node-Red (Chat id取得)

Wokwi ESP32 DHT22 + Telegram + Node-Red










WOKWI程式

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

#define DHTPIN 15       // 使用 GPIO15
#define DHTTYPE DHT22   // 如果你使用 DHT11,改成 DHT11

const char* ssid = "Wokwi-GUEST";
const char* password = "";
//const char* mqtt_server = "broker.hivemq.com";

const char* mqtt_server = "broker.mqttgo.io";
///const char* mqtt_server = "broker.hivemq.com";
//onst char* mqtt_server =  "test.mosquitto.org" ;

WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE);
//=================================
void setup_wifi() {
  delay(10);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}
//=================================
void reconnect() {
  while (!client.connected()) {
    if (client.connect("ESP32Client")) {
      // 成功連線後可以訂閱主題(如需)
    } else {
      delay(5000);
    }
  }
}
//=================================
void setup() {
  Serial.begin(115200);
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, 1883);

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

  float temp = dht.readTemperature();
  float hum = dht.readHumidity();
  Serial.print("溫度==>"+ String(temp));
  Serial.println( "濕度==>" + String(hum));
 
  if (!isnan(temp) && !isnan(hum)) {
    String payload = "{\"temperature\":" + String(temp) + ",\"humidity\":" + String(hum) + "}";
    client.publish("alex9ufo/home/sensor", payload.c_str());
  }

  delay(10000);
}
//=================================

Node-Red程式

[{"id":"a5057b39d764b18a","type":"ui_text","z":"9c38be55a5575910","group":"d9711674aaa78a70","order":1,"width":3,"height":1,"name":"溫度","label":"溫度 (°C)","format":"{{msg.payload}}","layout":"row-spread","className":"","x":430,"y":80,"wires":[]},{"id":"3bf577662b4a178b","type":"ui_text","z":"9c38be55a5575910","group":"d9711674aaa78a70","order":3,"width":3,"height":1,"name":"濕度","label":"濕度 (%)","format":"{{msg.payload}}","layout":"row-spread","className":"","x":430,"y":120,"wires":[]},{"id":"7d7417b8fe1a7dba","type":"mqtt in","z":"9c38be55a5575910","name":"MQTT in","topic":"alex9ufo/home/sensor","qos":"0","datatype":"auto-detect","broker":"810a2ad3535ef8a7","nl":false,"rap":true,"rh":0,"inputs":0,"x":80,"y":100,"wires":[["3c000c85da022f92","b58f329c7c85b517","977a1ca608d8c160"]]},{"id":"3c000c85da022f92","type":"function","z":"9c38be55a5575910","name":"function  ","func":"let temp = msg.payload.temperature;\nmsg.payload=temp;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":80,"wires":[["a5057b39d764b18a","e5bee21612305efd"]]},{"id":"b58f329c7c85b517","type":"function","z":"9c38be55a5575910","name":"function  ","func":"let hum = msg.payload.humidity;\nmsg.payload=hum;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":120,"wires":[["3bf577662b4a178b"]]},{"id":"your_telegram_sender_node_id","type":"telegram sender","z":"9c38be55a5575910","name":"","bot":"342323eb16fbab88","haserroroutput":true,"outputs":2,"x":470,"y":260,"wires":[["84f971f86ed6449d"],[]]},{"id":"5d7776a779c345d8","type":"debug","z":"9c38be55a5575910","name":"debug 347","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":330,"y":200,"wires":[]},{"id":"e5bee21612305efd","type":"debug","z":"9c38be55a5575910","name":"debug 348","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":450,"y":40,"wires":[]},{"id":"cc3d8c97542d7bf0","type":"template","z":"9c38be55a5575910","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"Wokwi DHT22目前{{payload}}\"}\n","output":"json","x":310,"y":260,"wires":[["your_telegram_sender_node_id"]]},{"id":"977a1ca608d8c160","type":"function","z":"9c38be55a5575910","name":"function  ","func":"var temperature = msg.payload.temperature;\nvar humidity = msg.payload.humidity;\nvar telegramMessage = `感測器數據:\\n溫度: ${temperature} °C\\n濕度: ${humidity} %`;\nmsg.payload = telegramMessage;\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":140,"y":260,"wires":[["cc3d8c97542d7bf0","5d7776a779c345d8"]]},{"id":"84f971f86ed6449d","type":"debug","z":"9c38be55a5575910","name":"debug 349","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":670,"y":260,"wires":[]},{"id":"d9711674aaa78a70","type":"ui_group","name":"感測器資訊","tab":"7ff0c1034122e8bc","order":1,"disp":true,"width":8,"collapse":false},{"id":"810a2ad3535ef8a7","type":"mqtt-broker","name":"broker.mqttgo.io","broker":"broker.mqttgo.io","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"5","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willRetain":"false","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"342323eb16fbab88","type":"telegram bot","botname":"@alex_ncutedu_bot","usernames":"","chatids":"","baseapiurl":"","testenvironment":false,"updatemode":"polling","addressfamily":"4","pollinterval":"300","usesocks":false,"sockshost":"","socksprotocol":"socks5","socksport":"6667","socksusername":"anonymous","sockspassword":"","bothost":"","botpath":"","localbothost":"0.0.0.0","localbotport":"8443","publicbotport":"8443","privatekey":"","certificate":"","useselfsignedcertificate":false,"sslterminated":false,"verboselogging":false},{"id":"7ff0c1034122e8bc","type":"ui_tab","name":"環境監控","icon":"dashboard","order":1}]

新增Bot

取得 Chat id



  • 首先,在瀏覽器中輸入「https://api.telegram.org/botToken/getUpdates」,(紅色字體改為由 @BotFather 給予的 token ,取得 token 則會得到一串的 JSON ,如果得到的是如以下的 JSON ,表示頻道中沒有廣播訊息(好像會以天為單位,前一天就算有廣播訊息,也不會列出)。
{"ok":true,"result":[]}
  • 可先在頻道中輸入「Hello World」,然後再回到前一個步驟,將會得到以下的 JSON:
{"ok":true,"result":[{"update_id":720650387,
"channel_post":{"message_id":22,"chat":{"id":-123456789,"title":"頻道名稱","username":"機器人名稱","type":"channel"},"date":1582014900,"text":"Hello World"}}]}

排序後如下:

{
	"ok":true,
	"result":[
	{
		"update_id":720650387,
		"channel_post":
		{
			"message_id":22,
			"chat":
			{
				"id":-123456789,
				"title":"頻道名稱",
				"username":"機器人名稱",
				"type":"channel"
			},
			"date":1582014900,
			"text":"Hello World"
		}
	}]
}
  • 找到其中的 “chat:” id”:-123456789,就是我們需要的 Chat ID,接著就可以藉著這組 Chat ID ,使用程式來對頻道發送廣播訊息了。
  • 取得 Chat ID 之後,也可以試著在瀏覽器中輸入

  • 「https://api.telegram.org/botToken/sendMessage?chat_id=-123456789&text=Hello World」,紅色字體須改為自己的 token ,以及剛剛取得的 Chat ID ,應該就可以順利在頻道中廣播訊息了。

2025年4月20日 星期日

Wokwi ESP32 DHT22 & LED + Node-Red + Telegram

 Wokwi ESP32 DHT22 & LED +  Node-Red + Telegram 








WOKWI程式

#include "WiFi.h";
#include <PubSubClient.h>;
#include <Wire.h>;
#include "DHTesp.h";
// DHT22 Pin
const int DHT_PIN = 15;
// LED Pin
const int ledPin = 4;

// Replace the next variables with your SSID/Password combination
const char* ssid = "Wokwi-GUEST";
const char* password = "";

// Add your MQTT Broker IP address, example:
//const char* mqtt_server = "192.168.1.144";
const char* mqtt_server = "broker.mqttgo.io";
///const char* mqtt_server = "broker.hivemq.com";
//onst char* mqtt_server =  "test.mosquitto.org" ;

WiFiClient espClient;
PubSubClient client(espClient);
DHTesp dhtSensor;

bool Send = false;  //true
String LEDjson = "";
long lastMsg = 0;
//=================================================================

//===================================================================
void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
//===================================================================
void callback(char* topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;
 
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();

  // Feel free to add more if statements to control more GPIOs with MQTT

  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off".
  // Changes the output state according to the message
  if (String(topic) == "alex9ufo/esp32/output") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
      digitalWrite(ledPin, HIGH);
      LEDjson ="LEDON";
      Send = true ;
      Serial.println(LEDjson);
    }
    else if(messageTemp == "off"){
      Serial.println("off");
      digitalWrite(ledPin, LOW);
      LEDjson ="LEDOFF";
      Send = true ;
      Serial.println(LEDjson);      
    }
  }
}
//===================================================================
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP32Client")) {
      Serial.println("connected");
      // Subscribe
      client.subscribe("alex9ufo/esp32/output");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
//===================================================================

//判斷 旗號Flash , Timer 是否為真
void LED_Message() {
  //判斷 旗號 Flash / timer  是否為真 ? 閃爍 定時
   
  ////判斷 旗號 Send 是否為真 回傳MQTT訊息到MQTT Broker 
  if (Send) {
    // Convert JSON string to character array
    Serial.print("Publish message: ");
    Serial.println(LEDjson);
    LEDjson.trim();
    client.publish("alex9ufo/esp32/ledstatus",LEDjson.c_str());
                       
    Send = false;    //處理過後 旗號 Send為假
  }

}
//================================================================
void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);

  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  client.subscribe("alex9ufo/esp32/output");
 
}
//===================================================================
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
 
  LED_Message();
  long now = millis();
  if (now - lastMsg > 5000) {
    lastMsg = now;
    TempAndHumidity  data = dhtSensor.getTempAndHumidity();
    String temp = String(data.temperature, 2);
    Serial.print("Temperature: ");
    Serial.println(temp);
    client.publish("alex9ufo/esp32/temperature", temp.c_str());
   
    String hum = String(data.humidity, 1);
    Serial.print("Humidity: ");
    Serial.println(hum);
    client.publish("alex9ufo/esp32/humidity", hum.c_str());
  }
}
//===================================================================

Node-Red程式

[{"id":"162ab9f0633e5aa7","type":"mqtt in","z":"6eac2d325758c0ee","name":"溫度 in","topic":"alex9ufo/esp32/temperature","qos":"1","datatype":"auto-detect","broker":"584db2f88f8050c2","nl":false,"rap":true,"rh":0,"inputs":0,"x":130,"y":60,"wires":[["af69ac16bc2b0591","03e3a9d73748e151"]]},{"id":"af69ac16bc2b0591","type":"template","z":"6eac2d325758c0ee","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"溫度: {{payload}}\"}\n","output":"json","x":330,"y":60,"wires":[["fc85c7b709f153fb"]]},{"id":"271761601837ee29","type":"debug","z":"6eac2d325758c0ee","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":720,"y":100,"wires":[]},{"id":"b005e958f8692d56","type":"mqtt in","z":"6eac2d325758c0ee","name":"濕度 in","topic":"alex9ufo/esp32/humidity","qos":"1","datatype":"auto-detect","broker":"584db2f88f8050c2","nl":false,"rap":true,"rh":0,"inputs":0,"x":130,"y":120,"wires":[["44da82e507f3a8f3","c2e8f13427529ab3"]]},{"id":"44da82e507f3a8f3","type":"template","z":"6eac2d325758c0ee","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"濕度: {{payload}}\"}\n","output":"json","x":330,"y":120,"wires":[["fc85c7b709f153fb"]]},{"id":"c2e8f13427529ab3","type":"debug","z":"6eac2d325758c0ee","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":280,"y":160,"wires":[]},{"id":"03e3a9d73748e151","type":"debug","z":"6eac2d325758c0ee","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":340,"y":20,"wires":[]},{"id":"fc85c7b709f153fb","type":"telegram sender","z":"6eac2d325758c0ee","name":"@ChinYi_EE_bot","bot":"a3ea8962e24bd44a","haserroroutput":true,"outputs":2,"x":530,"y":100,"wires":[["271761601837ee29"],[]]},{"id":"06ed93cda99156d2","type":"mqtt out","z":"6eac2d325758c0ee","name":"LED","topic":"alex9ufo/esp32/output","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"584db2f88f8050c2","x":330,"y":280,"wires":[]},{"id":"28ed1e43cae1a4fc","type":"template","z":"6eac2d325758c0ee","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"chatId\": 79165218469,\n\"type\":\"message\",\n\"content\":\"Temperature : {{payload}}\"}","output":"json","x":330,"y":240,"wires":[["be32280676986a30","fc85c7b709f153fb"]]},{"id":"be32280676986a30","type":"debug","z":"6eac2d325758c0ee","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":510,"y":240,"wires":[]},{"id":"6604e77fd4282820","type":"inject","z":"6eac2d325758c0ee","name":"LED ON","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"on","payloadType":"str","x":160,"y":240,"wires":[["28ed1e43cae1a4fc","06ed93cda99156d2"]]},{"id":"66441d60d26f19c7","type":"inject","z":"6eac2d325758c0ee","name":"LED OFF","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"off","payloadType":"str","x":160,"y":280,"wires":[["06ed93cda99156d2","28ed1e43cae1a4fc"]]},{"id":"bfa839590907cc0d","type":"telegram receiver","z":"6eac2d325758c0ee","name":"LED Control","bot":"a3ea8962e24bd44a","saveDataDir":"","filterCommands":false,"x":150,"y":360,"wires":[["d859efdb33b0aec3","aa0fa66c73e984a3"],[]]},{"id":"d859efdb33b0aec3","type":"function","z":"6eac2d325758c0ee","name":"function ","func":"var a= msg.payload.content;\nmsg.payload=a;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":360,"wires":[["9882cacf1ec89f1e","06ed93cda99156d2"]]},{"id":"9882cacf1ec89f1e","type":"debug","z":"6eac2d325758c0ee","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":500,"y":360,"wires":[]},{"id":"aa0fa66c73e984a3","type":"debug","z":"6eac2d325758c0ee","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":300,"y":400,"wires":[]},{"id":"5e177910f3e64146","type":"mqtt in","z":"6eac2d325758c0ee","name":"LED狀態","topic":"alex9ufo/esp32/ledstatus","qos":"2","datatype":"auto-detect","broker":"584db2f88f8050c2","nl":false,"rap":true,"rh":0,"inputs":0,"x":140,"y":200,"wires":[["fae1a563bbaaf8a8"]]},{"id":"fae1a563bbaaf8a8","type":"template","z":"6eac2d325758c0ee","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"Wokwi LED目前: {{payload}}\"}\n","output":"json","x":330,"y":200,"wires":[["fc85c7b709f153fb"]]},{"id":"584db2f88f8050c2","type":"mqtt-broker","name":"broker.mqttgo.io","broker":"broker.mqttgo.io","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"a3ea8962e24bd44a","type":"telegram bot","botname":"@ChinYi_EE_bot","usernames":"","chatids":"","baseapiurl":"","testenvironment":false,"updatemode":"polling","addressfamily":"4","pollinterval":300,"usesocks":false,"sockshost":"","socksprotocol":"socks5","socksport":6667,"socksusername":"anonymous","sockspassword":"","bothost":"","botpath":"","localbothost":"0.0.0.0","localbotport":8443,"publicbotport":8443,"privatekey":"","certificate":"","useselfsignedcertificate":false,"sslterminated":false,"verboselogging":false}]

2025年4月19日 星期六

作業4 WOKWI + Node-Red + SQlite + Telegram

 作業4  WOKWI + Node-Red + SQlite + Telegram

      <<需變更 Telegram聊天機器人 名稱>>









#include <WiFi.h>
extern "C" {
  #include "freertos/FreeRTOS.h"
  #include "freertos/timers.h"
}
#include <AsyncMQTT_ESP32.h>

//#include <MFRC522.h>
#include <Arduino.h>
//=========================
//  RFID-RC522 wire pin
//  SDA = 5   SCK =18
//  MOSI=23   MISO=19
//  RST = 4  
//  GND , VCC
//=========================
//MFRC522 程式庫  模擬mfrc522 送出卡號 PB可以控制
int LED1 = 23;
int LED2 = 22;
int LED3 = 21;
int LED4 = 19;

int inPin = 12;    // pushbutton connected to digital pin 12


//#define MQTT_HOST     "broker.mqtt-dashboard.com"
//#define MQTT_HOST     "broker.hivemq.com"
//#define MQTT_HOST       "test.mosquitto.org"  
#define MQTT_HOST     "broker.mqttgo.io"
#define MQTT_PORT       1883

#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""

AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;


const char *SubTopic1 = "alex9ufo/esp32/led";
const char *PubTopic2 = "alex9ufo/esp32/led_status";
const char *PubTopic3 = "alex9ufo/esp32/RFID";
const char *PubTopic4 = "alex9ufo/esp32/Starting";

//================================================================
bool Send = false;  //true
String LEDjson = "";
int Count= 0;
int val = 0;      // variable to store the read value
bool create=false;
bool Flash1 = false;
bool Flash2 = false;
bool Flash3 = false;
bool Flash4 = false;
//================================================================
void connectToWifi() {
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
//================================================================
void connectToMqtt() {
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
}
//================================================================
void WiFiEvent(WiFiEvent_t event)
{
  switch (event)
  {
#if USING_CORE_ESP32_CORE_V200_PLUS

    case ARDUINO_EVENT_WIFI_READY:
      Serial.println("WiFi ready");
      break;

    case ARDUINO_EVENT_WIFI_STA_START:
      Serial.println("WiFi STA starting");
      break;

    case ARDUINO_EVENT_WIFI_STA_CONNECTED:
      Serial.println("WiFi STA connected");
      break;

    case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
    case ARDUINO_EVENT_WIFI_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;

    case ARDUINO_EVENT_WIFI_STA_LOST_IP:
      Serial.println("WiFi lost IP");
      break;

    case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
      xTimerStart(wifiReconnectTimer, 0);
      break;
#else

    case SYSTEM_EVENT_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;

    case SYSTEM_EVENT_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
      xTimerStart(wifiReconnectTimer, 0);
      break;
#endif

    default:
      break;
  }
}
//================================================================
void onMqttConnect(bool sessionPresent) {
  Serial.println("Connected to MQTT.");
  Serial.print("Session present: ");
  Serial.println(sessionPresent);

  Serial.println("Connected to MQTT.");
  Serial.print("Session present: ");
  Serial.println(sessionPresent);

  uint16_t packetIdSub1 = mqttClient.subscribe(SubTopic1 , 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub1);

  //uint16_t packetIdSub2 = mqttClient.subscribe(SubTopic2, 2);
  //Serial.print("Subscribing at QoS 2, packetId: ");
  //Serial.println(packetIdSub2);

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

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  Serial.println("Disconnected from MQTT.");
  if (WiFi.isConnected()) {
    xTimerStart(mqttReconnectTimer, 0);
  }
}
//================================================================
void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
  Serial.println("Subscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
  Serial.print("  qos: ");
  Serial.println(qos);
}
//================================================================
void onMqttUnsubscribe(uint16_t packetId) {
  Serial.println("Unsubscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}
//================================================================
void onMqttPublish(uint16_t packetId) {
  Serial.print("Publish acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}
//================================================================
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
 
  String messageTemp;
  for (int i = 0; i < len; i++) {
    Serial.print((char)payload[i]);
    messageTemp += (char)payload[i];
  }

  if (strcmp(topic, SubTopic1) == 0) {
    // If the relay is on turn it off (and vice-versa)
    Serial.println();
    Serial.println(messageTemp);  
   
    if ((messageTemp) == "led1on") {
    digitalWrite(LED1, HIGH);  // Turn on the LED
    //ledState = true;  //ledState = ture HIGH
    //設定 各個 旗號
    LEDjson ="LED1ON";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }
  if ((messageTemp) == "led2on") {
    digitalWrite(LED2, HIGH);  // Turn on the LED
    //ledState = true;  //ledState = ture HIGH
    //設定 各個 旗號
    LEDjson ="LED2ON";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }
  if ((messageTemp) == "led3on") {
    digitalWrite(LED3, HIGH);  // Turn on the LED
    //ledState = true;  //ledState = ture HIGH
    //設定 各個 旗號
    LEDjson ="LED3ON";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }
  if ((messageTemp) == "led4on") {
    digitalWrite(LED4, HIGH);  // Turn on the LED
    //ledState = true;  //ledState = ture HIGH
    //設定 各個 旗號
    LEDjson ="LED4ON";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }

  if ((messageTemp) == "led1off" ) {
    digitalWrite(LED1, LOW); // Turn off the LED
    //ledState = false; //ledState = false LOW
    LEDjson ="LED1OFF";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }
  if ((messageTemp) == "led2off" ) {
    digitalWrite(LED2, LOW); // Turn off the LED
    //ledState = false; //ledState = false LOW
    LEDjson ="LED2OFF";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }

  if ((messageTemp) == "led3off" ) {
    digitalWrite(LED3, LOW); // Turn off the LED
    //ledState = false; //ledState = false LOW
    LEDjson ="LED3OFF";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }
  if ((messageTemp) == "led4off" ) {
    digitalWrite(LED4, LOW); // Turn off the LED
    //ledState = false; //ledState = false LOW
    LEDjson ="LED4OFF";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }
  if ((messageTemp) == "led1flash" ) {
    digitalWrite(LED1, HIGH); // Turn off the LED
    Flash1 = true;
    //Flash2 = false;
    //Flash3 = false;
    //Flash4 = false;
    LEDjson ="LED1FLASH";
    Send = true ;  
    Serial.println(LEDjson);      
  }
  if ((messageTemp) == "led2flash" ) {
    digitalWrite(LED2, HIGH); // Turn off the LED
    Flash2 = true;
    //Flash1 = false;
    //Flash3 = false;
    //Flash4 = false;
    LEDjson ="LED2FLASH";
    Send = true ;  
    Serial.println(LEDjson);      
  }
  if ((messageTemp) == "led3flash" ) {
    digitalWrite(LED3, HIGH); // Turn off the LED
    Flash3 = true;
    //Flash1 = false;
    //Flash2 = false;
    //Flash4 = false;
    LEDjson ="LED3FLASH";
    Send = true ;  
    Serial.println(LEDjson);      
  }
  if ((messageTemp) == "led4flash" ) {
    digitalWrite(LED4, HIGH); // Turn off the LED
    Flash4 = true;
    //Flash1 = false;
    //Flash2 = false;
    //Flash3 = false;
    LEDjson ="LED4FLASH";
    Send = true ;  
    Serial.println(LEDjson);      
  }

  if ((messageTemp) == "ledalloff" ) {
    digitalWrite(LED1, LOW); // Turn off the LED
    digitalWrite(LED2, LOW); // Turn off the LED
    digitalWrite(LED3, LOW); // Turn off the LED
    digitalWrite(LED4, LOW); // Turn off the LED
    //ledState = false; //ledState = false LOW
    LEDjson ="LEDALLOFF";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }

  if ((messageTemp) == "ledallon") {
    digitalWrite(LED1, HIGH);  // Turn on the LED
    digitalWrite(LED2, HIGH);  // Turn on the LED
    digitalWrite(LED3, HIGH);  // Turn on the LED
    digitalWrite(LED4, HIGH);  // Turn on the LED
   
    //ledState = true;  //ledState = ture HIGH
    //設定 各個 旗號
    LEDjson ="LEDALLON";
    Flash1 = false;
    Flash2 = false;
    Flash3 = false;
    Flash4 = false;
    Send = true ;
    Serial.println(LEDjson);
  }

  }
}
//================================================================
//判斷 旗號Flash , Timer 是否為真
void LED_Message() {
  //判斷 旗號 Flash / timer  是否為真 ? 閃爍 定時
 
   
  ////判斷 旗號 Send 是否為真 回傳MQTT訊息到MQTT Broker 
  if (Send) {
    // Convert JSON string to character array
    Serial.print("Publish message: ");
    Serial.println(LEDjson);
    LEDjson.trim();
    uint16_t packetIdPub1 = mqttClient.publish(PubTopic2, 1, true, LEDjson.c_str());                            
    Serial.printf("LED Published TO MQTT", PubTopic2, packetIdPub1);                            
    Send = false;    //處理過後 旗號 Send為假
  }

}
//================================================================
void setup() {
  Serial.begin(115200); // 初始化序列埠
  pinMode(LED1, OUTPUT);
  digitalWrite(LED1, LOW);  // Turn off the LED initially
  pinMode(LED2, OUTPUT);
  digitalWrite(LED2, LOW);  // Turn off the LED initially
  pinMode(LED3, OUTPUT);
  digitalWrite(LED3, LOW);  // Turn off the LED initially
  pinMode(LED4, OUTPUT);
  digitalWrite(LED4, LOW);  // Turn off the LED initially

  pinMode(inPin, INPUT);    // sets the digital pin 12 as input
  randomSeed(analogRead(0)); // 設定亂數種子,增加亂數的隨機性  

  //Initialize serial and wait for port to open:
  Serial.begin(115200);   // Initialize serial communications with the PC

  mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
  wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));

  WiFi.onEvent(WiFiEvent);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onSubscribe(onMqttSubscribe);
  mqttClient.onUnsubscribe(onMqttUnsubscribe);
  mqttClient.onMessage(onMqttMessage); //callback
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  // If your broker requires authentication (username and password), set them below
  //mqttClient.setCredentials("REPlACE_WITH_YOUR_USER", "REPLACE_WITH_YOUR_PASSWORD");
  connectToWifi();

  String temp1="Starting ESP32... ";
  uint16_t packetIdPub1 = mqttClient.publish(PubTopic4, 1, true, temp1.c_str());                            
  Serial.printf("RFID UID Number Published", PubTopic4, packetIdPub1);
}
//================================================================
void loop() {
  LED_Message();
  val = digitalRead(inPin);   // read the input pin
  if (val==LOW) create= false;
  if (val==HIGH) create= true;

if (create) {
    // 模擬 RFID UID 結構
    struct RFID_UID {
      uint8_t uidByte[10]; // UID 位元組陣列,最大長度為 10
      uint8_t size;        // UID 長度
    };
    // 建立一個 RFID UID 物件
    RFID_UID uid;
    // 設定 UID 資料
    uid.size = 4;
   
    for (int i = 0; i < uid.size; i++) {
      uid.uidByte[i] = random(256); // 生成 0-255 的亂數
    }


    // 顯示 UID
    Serial.print("UID: ");
    for (int i = 0; i < uid.size; i++) {
      Serial.print(uid.uidByte[i] < 0x10 ? " 0" : " "); // 補零
      Serial.print(uid.uidByte[i], HEX);             // 以十六進位格式輸出
    }
    Serial.println();

    String json = "{ \"uid\": \"";
    for (int i = 0; i < uid.size; i++) {
        json += String(uid.uidByte[i], HEX);
      }
    json += "\" }";

    json.trim();
    uint16_t packetIdPub1 = mqttClient.publish(PubTopic3, 1, true, json.c_str());                            
    Serial.printf("RFID UID Number Published : ", PubTopic3, packetIdPub1);                            
    Serial.println(json);
    Serial.println();
   
    if (val==HIGH)
    {
      Serial.println("Delay...");
      delay(500);
    }
 
  }


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




[ { "id": "508a83bf78d1af97", "type": "ui_switch", "z": "fcce0e6bead574e7", "name": "", "label": "LED1 ON OFF", "tooltip": "", "group": "7376e0c4dc8cc058", "order": 1, "width": 4, "height": 1, "passthru": true, "decouple": "false", "topic": "topic", "topicType": "msg", "style": "", "onvalue": "led1on", "onvalueType": "str", "onicon": "", "oncolor": "", "offvalue": "led1off", "offvalueType": "str", "officon": "", "offcolor": "", "animate": false, "className": "", "x": 1040, "y": 20, "wires": [ [ "6a97f1d3529e0cfd", "b799e713f3da2249" ] ] }, { "id": "20f5422869d00e3b", "type": "ui_switch", "z": "fcce0e6bead574e7", "name": "", "label": "LED2 ON OFF", "tooltip": "", "group": "7376e0c4dc8cc058", "order": 3, "width": 4, "height": 1, "passthru": true, "decouple": "false", "topic": "topic", "topicType": "msg", "style": "", "onvalue": "led2on", "onvalueType": "str", "onicon": "", "oncolor": "", "offvalue": "led2off", "offvalueType": "str", "officon": "", "offcolor": "", "animate": false, "className": "", "x": 1040, "y": 60, "wires": [ [ "6a97f1d3529e0cfd" ] ] }, { "id": "f2291e7009d6d78b", "type": "ui_switch", "z": "fcce0e6bead574e7", "name": "", "label": "LED3 ON OFF", "tooltip": "", "group": "7376e0c4dc8cc058", "order": 5, "width": 4, "height": 1, "passthru": true, "decouple": "false", "topic": "topic", "topicType": "msg", "style": "", "onvalue": "led3on", "onvalueType": "str", "onicon": "", "oncolor": "", "offvalue": "led3off", "offvalueType": "str", "officon": "", "offcolor": "", "animate": false, "className": "", "x": 1040, "y": 100, "wires": [ [ "6a97f1d3529e0cfd" ] ] }, { "id": "88f06c8d911ee9df", "type": "ui_switch", "z": "fcce0e6bead574e7", "name": "", "label": "LED4 ON OFF", "tooltip": "", "group": "7376e0c4dc8cc058", "order": 7, "width": 4, "height": 1, "passthru": true, "decouple": "false", "topic": "topic", "topicType": "msg", "style": "", "onvalue": "led4on", "onvalueType": "str", "onicon": "", "oncolor": "", "offvalue": "led4off", "offvalueType": "str", "officon": "", "offcolor": "", "animate": false, "className": "", "x": 1040, "y": 140, "wires": [ [ "6a97f1d3529e0cfd" ] ] }, { "id": "c70dbeb8107da82e", "type": "ui_button", "z": "fcce0e6bead574e7", "name": "", "group": "7376e0c4dc8cc058", "order": 9, "width": 6, "height": 1, "passthru": false, "label": "LED all ON", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "ledallon", "payloadType": "str", "topic": "topic", "topicType": "msg", "x": 1030, "y": 180, "wires": [ [ "6a97f1d3529e0cfd" ] ] }, { "id": "27fc93ca75339a2f", "type": "ui_button", "z": "fcce0e6bead574e7", "name": "", "group": "7376e0c4dc8cc058", "order": 10, "width": 6, "height": 1, "passthru": false, "label": "LED all OFF", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "ledalloff", "payloadType": "str", "topic": "topic", "topicType": "msg", "x": 1030, "y": 220, "wires": [ [ "6a97f1d3529e0cfd" ] ] }, { "id": "6a97f1d3529e0cfd", "type": "mqtt out", "z": "fcce0e6bead574e7", "name": "LED Control", "topic": "alex9ufo/esp32/led", "qos": "1", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "584db2f88f8050c2", "x": 1290, "y": 140, "wires": [] }, { "id": "b799e713f3da2249", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1240, "y": 40, "wires": [] }, { "id": "a1815bd178772a81", "type": "mqtt in", "z": "fcce0e6bead574e7", "name": "LED Status", "topic": "alex9ufo/esp32/led_status", "qos": "2", "datatype": "auto-detect", "broker": "584db2f88f8050c2", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 90, "y": 240, "wires": [ [ "653157f6067482cb", "2", "b7941493aef7ceba" ] ] }, { "id": "653157f6067482cb", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 240, "y": 400, "wires": [] }, { "id": "2", "type": "function", "z": "fcce0e6bead574e7", "name": "LED Dispatcher", "func": "// 建立一個陣列來裝每個輸出的訊息,預設都為 null\nlet outputs = Array(10).fill(null);\n\n// 根據 payload 決定要送出的輸出端口 (0~9)\nswitch (msg.payload) {\n case \"LED1ON\":\n outputs[0] = msg;\n break;\n case \"LED1OFF\":\n outputs[1] = msg;\n break;\n case \"LED2ON\":\n outputs[2] = msg;\n break;\n case \"LED2OFF\":\n outputs[3] = msg;\n break;\n case \"LED3ON\":\n outputs[4] = msg;\n break;\n case \"LED3OFF\":\n outputs[5] = msg;\n break;\n case \"LED4ON\":\n outputs[6] = msg;\n break;\n case \"LED4OFF\":\n outputs[7] = msg;\n break;\n case \"LEDALLON\":\n outputs[8] = msg;\n break;\n case \"LEDALLOFF\":\n outputs[9] = msg;\n break;\n default:\n return null;\n}\n\n// 回傳包含 10 個輸出的陣列\nreturn outputs;", "outputs": 10, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 260, "y": 240, "wires": [ [ "0a22d4a2657165ad", "f836ba8bb4d80649" ], [ "90d79b4c9d4b0773", "03ee844da78f3e80" ], [ "fbc38c9011e4c418", "053bc4bdad0549ed" ], [ "69a9a1509ba3e739", "e26cf9a59cba5bf2" ], [ "d44f7266d3524809", "e0cf3ebad64a422a" ], [ "29786589908dd6a7", "c390c4d38957ef83" ], [ "0d6635a689b7d6b0", "9b1c52b370485d97" ], [ "1b28cd3697bad642", "ec7ec922fcecb864" ], [ "f4bf4a7b5204983c", "b5d5226ae11f6768" ], [ "d617b4f4b928de16", "eecfaa191e534be4" ] ] }, { "id": "d617b4f4b928de16", "type": "function", "z": "fcce0e6bead574e7", "name": "function LEDALLOFF", "func": "if (msg.payload === \"LEDALLOFF\") {\n msg.payload = false;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 560, "wires": [ [ "f1ab102d6af41123" ] ] }, { "id": "f4bf4a7b5204983c", "type": "function", "z": "fcce0e6bead574e7", "name": "function LEDALLON", "func": "if (msg.payload === \"LEDALLON\") {\n msg.payload = true;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 500, "wires": [ [ "f1ab102d6af41123" ] ] }, { "id": "0a22d4a2657165ad", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED1ON", "func": "if (msg.payload === \"LED1ON\") {\n msg.payload = true;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 570, "y": 40, "wires": [ [ "1623401c00f3052c", "553292363b556395" ] ] }, { "id": "90d79b4c9d4b0773", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED1OFF", "func": "if (msg.payload === \"LED1OFF\") {\n msg.payload = false;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 570, "y": 80, "wires": [ [ "1623401c00f3052c", "553292363b556395" ] ] }, { "id": "1623401c00f3052c", "type": "ui_led", "z": "fcce0e6bead574e7", "order": 2, "group": "7376e0c4dc8cc058", "width": 2, "height": 1, "label": "1", "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": 810, "y": 80, "wires": [] }, { "id": "fbc38c9011e4c418", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED2ON", "func": "if (msg.payload === \"LED2ON\") {\n msg.payload = true;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 570, "y": 160, "wires": [ [ "37fad941c49aee36", "553292363b556395" ] ] }, { "id": "69a9a1509ba3e739", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED2OFF", "func": "if (msg.payload === \"LED2OFF\") {\n msg.payload = false;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 220, "wires": [ [ "37fad941c49aee36", "553292363b556395" ] ] }, { "id": "37fad941c49aee36", "type": "ui_led", "z": "fcce0e6bead574e7", "order": 4, "group": "7376e0c4dc8cc058", "width": 2, "height": 1, "label": "2", "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": 810, "y": 180, "wires": [] }, { "id": "d44f7266d3524809", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED3ON", "func": "if (msg.payload === \"LED3ON\") {\n msg.payload = true;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 280, "wires": [ [ "866d4531a00e4d06", "553292363b556395" ] ] }, { "id": "29786589908dd6a7", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED3OFF", "func": "if (msg.payload === \"LED3OFF\") {\n msg.payload = false;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 340, "wires": [ [ "866d4531a00e4d06", "553292363b556395" ] ] }, { "id": "866d4531a00e4d06", "type": "ui_led", "z": "fcce0e6bead574e7", "order": 6, "group": "7376e0c4dc8cc058", "width": 2, "height": 1, "label": "3", "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": 810, "y": 280, "wires": [] }, { "id": "0d6635a689b7d6b0", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED4ON", "func": "if (msg.payload === \"LED4ON\") {\n msg.payload = true;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 400, "wires": [ [ "e43da95604e0e558", "553292363b556395" ] ] }, { "id": "1b28cd3697bad642", "type": "function", "z": "fcce0e6bead574e7", "name": "function LED4OFF", "func": "if (msg.payload === \"LED4OFF\") {\n msg.payload = false;\n return msg;\n} else {\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 440, "wires": [ [ "e43da95604e0e558", "553292363b556395" ] ] }, { "id": "e43da95604e0e558", "type": "ui_led", "z": "fcce0e6bead574e7", "order": 8, "group": "7376e0c4dc8cc058", "width": 2, "height": 1, "label": "4", "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": 810, "y": 420, "wires": [] }, { "id": "f1ab102d6af41123", "type": "link out", "z": "fcce0e6bead574e7", "name": "link out 5", "mode": "link", "links": [ "60c56a73fae93760" ], "x": 745, "y": 540, "wires": [] }, { "id": "60c56a73fae93760", "type": "link in", "z": "fcce0e6bead574e7", "name": "link in 7", "links": [ "f1ab102d6af41123" ], "x": 725, "y": 140, "wires": [ [ "1623401c00f3052c", "37fad941c49aee36", "866d4531a00e4d06", "e43da95604e0e558", "553292363b556395" ] ] }, { "id": "553292363b556395", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 820, "y": 220, "wires": [] }, { "id": "9a349abe035372bb", "type": "function", "z": "fcce0e6bead574e7", "name": "CREATE DATABASE", "func": "//CREATE TABLE RFIDUID (\n//id INTEGER,\n//UID TEXT,\n//Date DATE,\n//Time TIME,\n//PRIMARY KEY (id)\n//);\n//CREATE TABLE LEDSTATUS (id INTEGER,UID TEXT,Date DATE,Time TIME,PRIMARY KEY (id));\nmsg.topic = \"CREATE TABLE RFIDUID (id INTEGER,UID TEXT,Date DATE,Time TIME,PRIMARY KEY (id))\";\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1220, "y": 560, "wires": [ [ "a2d7d7399a152e7d" ] ] }, { "id": "955a2e1ec6b03d9a", "type": "ui_button", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "order": 2, "width": 3, "height": 1, "passthru": false, "label": "建立RFID資料庫", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "建立資料庫", "payloadType": "str", "topic": "topic", "topicType": "msg", "x": 1000, "y": 560, "wires": [ [ "9a349abe035372bb", "27477e6cbb0d1ab0" ] ] }, { "id": "1d13d8d27746f41f", "type": "function", "z": "fcce0e6bead574e7", "name": "INSERT", "func": "var 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(); //秒\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}\nvar var_date = yyyy+'/'+MM+'/'+dd;\nvar var_time = h+':'+m+':'+s;\n\nvar myUID = msg.payload.uid;\n\n\nmsg.topic = \"INSERT INTO RFIDUID ( UID , Date , Time ) VALUES ($myUID, $var_date , $var_time ) \" ;\nmsg.payload = [myUID, var_date , var_time ]\nreturn msg;\n\n\n//INSERT INTO LEDSTATUS (\n//id INTEGER,\n//UID TEXT,\n//Date DATE,\n//Time TIME,\n//PRIMARY KEY (id)\n//);\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1140, "y": 420, "wires": [ [ "ceaf38b381bc12e0" ] ] }, { "id": "ceaf38b381bc12e0", "type": "sqlite", "z": "fcce0e6bead574e7", "mydb": "f5c97c74cc496505", "sqlquery": "msg.topic", "sql": "", "name": "RFID_2025EX2", "x": 1340, "y": 420, "wires": [ [ "95a108ee567f790d", "5ba82d08c111b413" ] ] }, { "id": "ce776f39256a83d6", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug ", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 1590, "y": 560, "wires": [] }, { "id": "95a108ee567f790d", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug ", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 1530, "y": 420, "wires": [] }, { "id": "f19ba4f89182c827", "type": "ui_button", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "order": 1, "width": 3, "height": 1, "passthru": false, "label": "檢視資料庫資料", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "檢視資料", "payloadType": "str", "topic": "topic", "topicType": "msg", "x": 1000, "y": 500, "wires": [ [ "5ba82d08c111b413", "27477e6cbb0d1ab0" ] ] }, { "id": "5ba82d08c111b413", "type": "function", "z": "fcce0e6bead574e7", "name": "檢視資料", "func": "//INSERT INTO RFIDUID (\n//id INTEGER,\n//UID TEXT,\n//Date DATE,\n//Time TIME,\n//PRIMARY KEY (id)\n//);\n\n//SELECT * FROM RFIDUID ORDER BY id DESC LIMIT 50;\n\nmsg.topic = \"SELECT * FROM RFIDUID ORDER BY id DESC LIMIT 50\";\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1300, "y": 500, "wires": [ [ "d75616872c411e2a" ] ] }, { "id": "0125ad9a2c641256", "type": "ui_table", "z": "fcce0e6bead574e7", "group": "c1460b15f679e676", "name": "", "order": 4, "width": 9, "height": 5, "columns": [], "outputs": 0, "cts": false, "x": 1630, "y": 500, "wires": [] }, { "id": "b344e00afda936d9", "type": "ui_button", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "order": 3, "width": 3, "height": 1, "passthru": false, "label": "刪除所有資料 ", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "刪除所有資料 ", "payloadType": "str", "topic": "topic", "topicType": "msg", "x": 1000, "y": 620, "wires": [ [ "6f036d83ed92ce38", "27477e6cbb0d1ab0" ] ] }, { "id": "b57e0d922b95bf93", "type": "function", "z": "fcce0e6bead574e7", "name": "DELETE ALL DATA", "func": "//CREATE TABLE RFIDUID (\n//id INTEGER,\n//UID TEXT,\n//Date DATE,\n//Time TIME,\n//PRIMARY KEY (id)\n//);\n//CREATE TABLE LEDSTATUS (id INTEGER,UID TEXT,Date DATE,Time TIME,PRIMARY KEY (id));\nmsg.topic = \"DELETE from RFIDUID\";\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1570, "y": 620, "wires": [ [ "6a6d7897c3cfb419" ] ] }, { "id": "6f036d83ed92ce38", "type": "ui_toast", "z": "fcce0e6bead574e7", "position": "prompt", "displayTime": "3", "highlight": "", "sendall": true, "outputs": 1, "ok": "OK", "cancel": "Cancel", "raw": true, "className": "", "topic": "", "name": "", "x": 1190, "y": 620, "wires": [ [ "a0ef9725fe77f51f" ] ] }, { "id": "a0ef9725fe77f51f", "type": "function", "z": "fcce0e6bead574e7", "name": "OK or Cancel", "func": "var topic=msg.payload;\nif (topic==\"\"){\n return [msg,null];\n \n}\nif (topic==\"Cancel\"){\n return [null,msg];\n \n}\nreturn msg;", "outputs": 2, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1360, "y": 620, "wires": [ [ "b57e0d922b95bf93" ], [] ] }, { "id": "27477e6cbb0d1ab0", "type": "ui_audio", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "voice": "Microsoft Hanhan - Chinese (Traditional, Taiwan)", "always": true, "x": 1145, "y": 520, "wires": [], "l": false }, { "id": "8601544629976bf3", "type": "link out", "z": "fcce0e6bead574e7", "name": "link out 14", "mode": "link", "links": [ "5673b5e03b67335b" ], "x": 1745, "y": 560, "wires": [] }, { "id": "5673b5e03b67335b", "type": "link in", "z": "fcce0e6bead574e7", "name": "link in 17", "links": [ "8601544629976bf3" ], "x": 1815, "y": 560, "wires": [ [ "5ba82d08c111b413" ] ] }, { "id": "2e1dafb86b158821", "type": "mqtt in", "z": "fcce0e6bead574e7", "name": "RFID in", "topic": "alex9ufo/esp32/RFID", "qos": "1", "datatype": "auto-detect", "broker": "584db2f88f8050c2", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 970, "y": 420, "wires": [ [ "1d13d8d27746f41f", "8f883ca3e2e45fba", "2175a631874bfc3c", "4408606c88079552", "2735e8f8d87d3217" ] ] }, { "id": "d75616872c411e2a", "type": "sqlite", "z": "fcce0e6bead574e7", "mydb": "f5c97c74cc496505", "sqlquery": "msg.topic", "sql": "", "name": "RFID_2025EX2", "x": 1460, "y": 500, "wires": [ [ "0125ad9a2c641256" ] ] }, { "id": "a2d7d7399a152e7d", "type": "sqlite", "z": "fcce0e6bead574e7", "mydb": "f5c97c74cc496505", "sqlquery": "msg.topic", "sql": "", "name": "RFID_2025EX2", "x": 1420, "y": 560, "wires": [ [ "ce776f39256a83d6" ] ] }, { "id": "6a6d7897c3cfb419", "type": "sqlite", "z": "fcce0e6bead574e7", "mydb": "f5c97c74cc496505", "sqlquery": "msg.topic", "sql": "", "name": "RFID_2025EX2", "x": 1760, "y": 620, "wires": [ [ "8601544629976bf3" ] ] }, { "id": "8f883ca3e2e45fba", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload.uid", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 1140, "y": 460, "wires": [] }, { "id": "2175a631874bfc3c", "type": "function", "z": "fcce0e6bead574e7", "name": "增加 日期 時間", "func": "var 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(); //秒\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}\nvar var_date = yyyy+'/'+MM+'/'+dd;\nvar var_time = h+':'+m+':'+s;\n\nvar myUID = msg.payload.uid;\n\n\nmsg.payload=\"新增一筆:\"+ myUID +\", 日期: \"+ var_date +\", 時間:\"+var_time;\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1160, "y": 380, "wires": [ [ "2390120793a57c4c" ] ] }, { "id": "feaf4daafd32f27d", "type": "comment", "z": "fcce0e6bead574e7", "name": "LINE Messaging API", "info": "", "x": 1550, "y": 340, "wires": [] }, { "id": "2390120793a57c4c", "type": "function", "z": "fcce0e6bead574e7", "name": "LINE Messaging API", "func": "//CHANNEL_ACCESS_TOKEN = 'Messaging API Token';\nCHANNEL_ACCESS_TOKEN = 'P7R4jd35usv1YhlJaC9HGXwcq6G0YknpvDxOb356AnOGHt5MPpzXmJrxj5L9OY5Z70h1DSdKRGr2/6Q8cN0bVoh6PcUMISbfncKvnMmv2HG5GCR+HMgpPj2LQYqOLDKgDqUGchzrkgkrG1KhnhfnugdB04t89/1O/w1cDnyilFU=';\nUSER_ID = 'U60f091afaaf1d41e21ace45205bfd3cf'; //'使用者ID(不是Line ID)';\n\nvar msg1=msg.payload;\n\nmessage = {\n type:'text',\n text:'Line Developers傳送的訊息:'+msg1\n};\n\n\nheaders = {\n 'Content-Type': 'application/json; charset=UTF-8',\n 'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,\n};\npayload = {\n 'to': USER_ID,\n 'messages': [message]\n};\nmsg.headers = headers;\nmsg.payload = payload;\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1380, "y": 380, "wires": [ [ "5d4c661a5d375779" ] ] }, { "id": "5d4c661a5d375779", "type": "http request", "z": "fcce0e6bead574e7", "name": "LINE Developers Messaging API 傳送", "method": "POST", "ret": "txt", "paytoqs": "ignore", "url": "https://api.line.me/v2/bot/message/push", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 1650, "y": 380, "wires": [ [ "f9cb0f54c0825f98" ] ] }, { "id": "f9cb0f54c0825f98", "type": "debug", "z": "fcce0e6bead574e7", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 1910, "y": 380, "wires": [] }, { "id": "bc3b9524ad279dd6", "type": "telegram sender", "z": "fcce0e6bead574e7", "name": "@ChinYi_EE_bot", "bot": "a3ea8962e24bd44a", "haserroroutput": true, "outputs": 2, "x": 1510, "y": 280, "wires": [ [ "5f3881a4cf8b704f" ], [] ] }, { "id": "5f3881a4cf8b704f", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1740, "y": 280, "wires": [] }, { "id": "ebac5c36991c340d", "type": "template", "z": "fcce0e6bead574e7", "name": "", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"新增一筆 : {{payload}}\"}\n", "output": "json", "x": 1350, "y": 280, "wires": [ [ "bc3b9524ad279dd6" ] ] }, { "id": "843a28cca1d86813", "type": "comment", "z": "fcce0e6bead574e7", "name": "TeleGram Messaging API", "info": "", "x": 1570, "y": 160, "wires": [] }, { "id": "8c3fcf85e0a58cdc", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1340, "y": 340, "wires": [] }, { "id": "4408606c88079552", "type": "function", "z": "fcce0e6bead574e7", "name": "增加 日期 時間", "func": "var 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(); //秒\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}\nvar var_date = yyyy+MM+dd;\nvar var_time = h+':'+m+':'+s;\n\nvar myuid = msg.payload.uid;\n\nmsg.payload= myuid +\", 日期: \"+ var_date +\", 時間:\"+var_time;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1160, "y": 340, "wires": [ [ "ebac5c36991c340d", "8c3fcf85e0a58cdc" ] ] }, { "id": "b7941493aef7ceba", "type": "template", "z": "fcce0e6bead574e7", "name": "", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "\n{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"LED狀態 : {{payload}}\"}\n", "output": "json", "x": 150, "y": 540, "wires": [ [ "9d598c71ba700b7c" ] ] }, { "id": "9d598c71ba700b7c", "type": "telegram sender", "z": "fcce0e6bead574e7", "name": "@ChinYi_EE_bot", "bot": "a3ea8962e24bd44a", "haserroroutput": true, "outputs": 2, "x": 310, "y": 540, "wires": [ [], [] ] }, { "id": "f836ba8bb4d80649", "type": "function", "z": "fcce0e6bead574e7", "name": "function led1on speak", "func": "if (msg.payload === \"LED1ON\") {\n msg.payload = \"L E D 一 號 亮\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 580, "y": 20, "wires": [ [ "3839f360be83125a" ] ] }, { "id": "3839f360be83125a", "type": "ui_audio", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "voice": "Microsoft Hanhan - Chinese (Traditional, Taiwan)", "always": true, "x": 755, "y": 20, "wires": [], "l": false }, { "id": "03ee844da78f3e80", "type": "function", "z": "fcce0e6bead574e7", "name": "function led1off speak", "func": "if (msg.payload === \"LED1OFF\") {\n msg.payload = \"L E D 一 號 滅\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 580, "y": 100, "wires": [ [ "3839f360be83125a" ] ] }, { "id": "e26cf9a59cba5bf2", "type": "function", "z": "fcce0e6bead574e7", "name": "function led2off speak", "func": "if (msg.payload === \"LED2OFF\") {\n msg.payload = \"L E D 二 號 滅\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 200, "wires": [ [ "953a51310d12cdfa" ] ] }, { "id": "053bc4bdad0549ed", "type": "function", "z": "fcce0e6bead574e7", "name": "function led2on speak", "func": "if (msg.payload === \"LED2ON\") {\n msg.payload = \"L E D 二 號 亮\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 580, "y": 140, "wires": [ [ "953a51310d12cdfa" ] ] }, { "id": "953a51310d12cdfa", "type": "ui_audio", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "voice": "Microsoft Hanhan - Chinese (Traditional, Taiwan)", "always": true, "x": 805, "y": 120, "wires": [], "l": false }, { "id": "e0cf3ebad64a422a", "type": "function", "z": "fcce0e6bead574e7", "name": "function led3on speak", "func": "if (msg.payload === \"LED3ON\") {\n msg.payload = \"L E D 三 號 亮\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 260, "wires": [ [ "12d376ba4e7f14a6" ] ] }, { "id": "c390c4d38957ef83", "type": "function", "z": "fcce0e6bead574e7", "name": "function led3off speak", "func": "if (msg.payload === \"LED3OFF\") {\n msg.payload = \"L E D 三 號 滅\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 320, "wires": [ [ "12d376ba4e7f14a6" ] ] }, { "id": "12d376ba4e7f14a6", "type": "ui_audio", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "voice": "Microsoft Hanhan - Chinese (Traditional, Taiwan)", "always": true, "x": 775, "y": 320, "wires": [], "l": false }, { "id": "9b1c52b370485d97", "type": "function", "z": "fcce0e6bead574e7", "name": "function led4on speak", "func": "if (msg.payload === \"LED4ON\") {\n msg.payload = \"L E D 四 號 亮\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 380, "wires": [ [ "94ad2b4fe4204984" ] ] }, { "id": "ec7ec922fcecb864", "type": "function", "z": "fcce0e6bead574e7", "name": "function led4off speak", "func": "if (msg.payload === \"LED4OFF\") {\n msg.payload = \"L E D 四 號 滅\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 460, "wires": [ [ "94ad2b4fe4204984" ] ] }, { "id": "94ad2b4fe4204984", "type": "ui_audio", "z": "fcce0e6bead574e7", "name": "", "group": "c1460b15f679e676", "voice": "Microsoft Hanhan - Chinese (Traditional, Taiwan)", "always": true, "x": 765, "y": 480, "wires": [], "l": false }, { "id": "b5d5226ae11f6768", "type": "function", "z": "fcce0e6bead574e7", "name": "function ledallon speak", "func": "if (msg.payload === \"LEDALLON\") {\n msg.payload = \"L E D 全 亮\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 520, "wires": [ [ "94ad2b4fe4204984" ] ] }, { "id": "eecfaa191e534be4", "type": "function", "z": "fcce0e6bead574e7", "name": "function ledoff speak", "func": "if (msg.payload === \"LEDALLOFF\") {\n msg.payload = \"L E D 全 滅\";\n return msg;\n} else {\n return null;\n}\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 580, "wires": [ [ "94ad2b4fe4204984" ] ] }, { "id": "2735e8f8d87d3217", "type": "function", "z": "fcce0e6bead574e7", "name": "get UID", "func": "\nvar myuid = msg.payload.uid;\n\nmsg.payload= myuid;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1140, "y": 300, "wires": [ [ "8e6072f5689e98ca", "27477e6cbb0d1ab0" ] ] }, { "id": "8e6072f5689e98ca", "type": "debug", "z": "fcce0e6bead574e7", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1280, "y": 240, "wires": [] }, { "id": "7376e0c4dc8cc058", "type": "ui_group", "name": "LED控制", "tab": "82f3819207ab5853", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "584db2f88f8050c2", "type": "mqtt-broker", "name": "broker.mqttgo.io", "broker": "broker.mqttgo.io", "port": "1883", "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "c1460b15f679e676", "type": "ui_group", "name": "RFID 資料", "tab": "82f3819207ab5853", "order": 2, "disp": true, "width": 9, "collapse": false, "className": "" }, { "id": "f5c97c74cc496505", "type": "sqlitedb", "db": "2025EX2_RFID.db", "mode": "RWC" }, { "id": "a3ea8962e24bd44a", "type": "telegram bot", "botname": "@ChinYi_EE_bot", "usernames": "", "chatids": "", "baseapiurl": "", "testenvironment": false, "updatemode": "polling", "addressfamily": "4", "pollinterval": 300, "usesocks": false, "sockshost": "", "socksprotocol": "socks5", "socksport": 6667, "socksusername": "anonymous", "sockspassword": "", "bothost": "", "botpath": "", "localbothost": "0.0.0.0", "localbotport": 8443, "publicbotport": 8443, "privatekey": "", "certificate": "", "useselfsignedcertificate": false, "sslterminated": false, "verboselogging": false }, { "id": "82f3819207ab5853", "type": "ui_tab", "name": "WOKWI RFID", "icon": "dashboard", "order": 142, "disabled": false, "hidden": false } ]

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...