2025年10月25日 星期六

作業4 準備工作

 作業4 準備工作




DB_NAME = "rfid_node-red.db"

MQTT_BROKER = "broker.hivemq.com"

MQTT_PORT = 1883

TOPIC_RFID_UID = "alex9ufo/rfid/UID"

TOPIC_LED_CONTROL = "alex9ufo/rfid/led"

TOPIC_LED_STATUS = "alex9ufo/rfid/ledStatus"


Node-Red程式

[{"id":"ca7e01ca8654162f","type":"telegram receiver","z":"448157ebc5541371","name":"","bot":"457874f8aa8a857a","saveDataDir":"","filterCommands":true,"x":110,"y":40,"wires":[["9e865f658c3f6af9"],[]]},{"id":"dc882fef65c76133","type":"function","z":"448157ebc5541371","name":"根據指令發佈 MQTT 訊息","func":"if (msg.payload === \"/on\") {\n    msg.topic = \"alex9ufo/rfid/led\";\n    msg.payload = \"on\";  // 開啟綠色 LED\n} else if (msg.payload === \"/off\") {\n    msg.topic = \"alex9ufo/rfid/led\";\n    msg.payload = \"off\"; // 關閉 LED\n} else if (msg.payload === \"/flash\") {\n    msg.topic = \"alex9ufo/rfid/led\";\n    msg.payload = \"flash\"; // LED 交替閃爍\n} else if (msg.payload === \"/timer\") {\n    msg.topic = \"alex9ufo/rfid/led\";\n    msg.payload = \"timer\"; // LED 定時 10 秒後關閉\n}\nreturn msg;\n//function 根據指令來發佈 MQTT 訊息","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":40,"wires":[["7ec09b4c30e9b6cf"]]},{"id":"7ec09b4c30e9b6cf","type":"mqtt out","z":"448157ebc5541371","name":"","topic":"alex9ufo/rfid/led","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e93144c18f3d6409","x":680,"y":40,"wires":[]},{"id":"13a8d28ef336440f","type":"mqtt in","z":"448157ebc5541371","name":"","topic":"alex9ufo/rfid/led","qos":"2","datatype":"auto-detect","broker":"e93144c18f3d6409","nl":false,"rap":true,"rh":0,"inputs":0,"x":100,"y":160,"wires":[["6610796333c1f034","67311733e039e4b1","e9e6a74a585f3b6c"]]},{"id":"9e865f658c3f6af9","type":"function","z":"448157ebc5541371","name":"function","func":"var content= msg.payload.content;\nmsg.payload=content;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":40,"wires":[["dc882fef65c76133"]]},{"id":"2adb7ad76def92ca","type":"ui_led","z":"448157ebc5541371","order":1,"group":"5ed27e92f756bcf4","width":3,"height":2,"label":"","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"#ff0000","value":"false","valueType":"bool"},{"color":"#008000","value":"true","valueType":"bool"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":true,"name":"","x":750,"y":160,"wires":[]},{"id":"6610796333c1f034","type":"function","z":"448157ebc5541371","name":"function","func":"var content = msg.payload;\n\nif (content === 'on') {\n    msg.payload = true;\n    // Route to output 1\n    return [msg, null, null, null];\n}\n\nif (content === 'off') {\n    msg.payload = false;\n    // Route to output 2\n    return [null, msg, null, null];\n}\n\nif (content === 'flash') {\n    msg.payload = true;\n    // Route to output 3\n    return [null, null, msg, null];\n}\n\nif (content === 'timer') {\n    msg.payload = true;\n    // Route to output 4\n    return [null, null, null, msg]; // Changed to route 'timer' to the 4th output\n}\n\n// Optional: If none of the conditions are met, you can return 'null' to discard the message\n// or return [msg] to pass the original message through the first output.\n// For this example, we'll return null to stop the message.\nreturn null;","outputs":4,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":180,"wires":[["2adb7ad76def92ca","48b63713aaa717b1"],["2adb7ad76def92ca","48b63713aaa717b1"],["8e4c7be415272248","48b63713aaa717b1"],["b340bf7e95798e33","2adb7ad76def92ca","48b63713aaa717b1"]]},{"id":"b340bf7e95798e33","type":"delay","z":"448157ebc5541371","name":"","pauseType":"delay","timeout":"10","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":400,"y":320,"wires":[["3f72babf6b7bde78"]]},{"id":"8e4c7be415272248","type":"delay","z":"448157ebc5541371","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":450,"y":220,"wires":[["2adb7ad76def92ca","7c61b065db9a43b5"]]},{"id":"3f72babf6b7bde78","type":"function","z":"448157ebc5541371","name":"function","func":"msg.payload=false;\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":320,"wires":[["2adb7ad76def92ca"]]},{"id":"48b63713aaa717b1","type":"debug","z":"448157ebc5541371","name":"debug 363","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":510,"y":140,"wires":[]},{"id":"ce3cb5da10fc8fde","type":"function","z":"448157ebc5541371","name":"function","func":"msg.payload = !msg.payload;\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":280,"wires":[["8e4c7be415272248"]]},{"id":"66070cb0acfb18ce","type":"mqtt in","z":"448157ebc5541371","name":"ledStatus","topic":"alex9ufo/rfid/ledStatus","qos":"1","datatype":"auto-detect","broker":"e93144c18f3d6409","nl":false,"rap":true,"rh":0,"inputs":0,"x":80,"y":420,"wires":[["a2a05e599a1c2803"]]},{"id":"a2a05e599a1c2803","type":"function","z":"448157ebc5541371","name":"根據指令發佈 MQTT 訊息","func":"\nif (msg.payload === \"ON\") {\n    msg.payload = \"LED Status: on\";  // 開啟綠色 LED\n} else if (msg.payload === \"OFF\") {\n    msg.payload = \"LED Status: off\"; // 關閉 LED\n} else if (msg.payload === \"FLASH\") {\n    msg.payload = \"LED Status: flash\"; // LED 交替閃爍\n} else if (msg.payload === \"TIMER\") {\n    msg.payload = \"LED Status: timer\"; // LED 定時 10 秒後關閉\n}\nreturn msg;\n//function 根據指令來發佈 MQTT 訊息","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":420,"wires":[["cf9ed47acf13328f","ccd143a24325d0cb"]]},{"id":"3b246f02576fb2c4","type":"telegram sender","z":"448157ebc5541371","name":"","bot":"457874f8aa8a857a","haserroroutput":false,"outputs":1,"x":710,"y":420,"wires":[[]]},{"id":"8623eccb1262afa5","type":"mqtt out","z":"448157ebc5541371","name":"ledStatus","topic":"alex9ufo/rfid/ledStatus","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e93144c18f3d6409","x":540,"y":360,"wires":[]},{"id":"67311733e039e4b1","type":"function","z":"448157ebc5541371","name":"根據指令發佈 MQTT 訊息","func":"if (msg.payload === \"on\") {\n    msg.topic = \"alex9ufo/rfid/ledStatus\";\n    msg.payload = \"ON\";  // 開啟綠色 LED\n} else if (msg.payload === \"off\") {\n    msg.topic = \"alex9ufo/rfid/ledStatus\";\n    msg.payload = \"OFF\"; // 關閉 LED\n} else if (msg.payload === \"flash\") {\n    msg.topic = \"alex9ufo/rfid/ledStatus\";\n    msg.payload = \"FLASH\"; // LED 交替閃爍\n} else if (msg.payload === \"timer\") {\n    msg.topic = \"alex9ufo/rfid/ledStatus\";\n    msg.payload = \"TIMER\"; // LED 定時 10 秒後關閉\n}\nreturn msg;\n//function 根據指令來發佈 MQTT 訊息","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":360,"wires":[["8623eccb1262afa5"]]},{"id":"cf9ed47acf13328f","type":"debug","z":"448157ebc5541371","name":"debug 365","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":490,"y":460,"wires":[]},{"id":"ccd143a24325d0cb","type":"template","z":"448157ebc5541371","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"{{payload}}\"}","output":"json","x":550,"y":420,"wires":[["3b246f02576fb2c4"]]},{"id":"e9e6a74a585f3b6c","type":"function","z":"448157ebc5541371","name":"global.set","func":"var ledstatus = msg.payload;\n\n// 2. 將值設定為 Global 變數\nglobal.set(\"myledStatus\", ledstatus);\n\n// 3. 返回訊息,以便流程繼續\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":120,"wires":[[]]},{"id":"7c61b065db9a43b5","type":"function","z":"448157ebc5541371","name":"global.get","func":"// 1. 取得 Global 變數的值\n//global.set(\"myledStatus\", ledstatus);\nvar myValue = global.get(\"myledStatus\");\nif (myValue=='flash'){\n    return [msg,null];\n    }\nelse    \n    return [true,true];","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":280,"wires":[["ce3cb5da10fc8fde"],[]]},{"id":"a100deb0624e7c6b","type":"sqlite","z":"448157ebc5541371","mydb":"04085aab75f5ad41","sqlquery":"msg.topic","sql":"","name":"RFID","x":530,"y":780,"wires":[["1184a6ff8873cab5"]]},{"id":"ccec8a03b3ed4d2e","type":"function","z":"448157ebc5541371","name":"組合刪除一筆 SQL","func":"var id = flow.get('delete_id') || msg.payload;\nif(!id) return null;\nmsg.topic = `DELETE FROM rfid_logs WHERE id= $id`;\nmsg.payload = [id];\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":700,"wires":[["640e917b338f3959","062d62b2355724f6"]]},{"id":"717f1b8d1458c3d6","type":"function","z":"448157ebc5541371","name":"組合新增 SQL","func":"var memo, LEDorRFID ;\n\nif (msg.payload === \"ON\") {\n    LEDorRFID = \"ON\";\n    memo = \"LED Status: on\";  // 開啟綠色 LED\n\n} else if (msg.payload === \"OFF\") {\n    LEDorRFID = \"OFF\";\n    memo = \"LED Status: off\"; // 關閉 LED\n} else if (msg.payload === \"FLASH\") {\n    LEDorRFID = \"FLASH\";\n    memo = \"LED Status: flash\"; // LED 交替閃爍\n} else if (msg.payload === \"TIMER\") {\n    LEDorRFID = \"TIMER\";\n    memo = \"LED Status: timer\"; // LED 定時 10 秒後關閉\n}\n\n\n\n// 建立一個 Date 物件,它包含運行 Node-RED 的電腦的當前時間\nvar now = new Date();\n// --- 提取日期時間的不同格式 ---\n// 1. 完整的 ISO 格式 (例如: 2025-10-25T03:28:08.500Z)\nvar isoString = now.toISOString();\n\n// 2. YYYY-MM-DD (日期部分)\n// slice(0, 10) 會擷取 ISO 字串的前 10 個字元\nvar dateOnly = now.toISOString().slice(0, 10); \n\n// 3. HH:MM:SS (時間部分)\n// toTimeString() 輸出類似 \"11:28:08 GMT+0800 (CST)\" 的字串\n// slice(0, 8) 會擷取開頭的 HH:MM:SS\nvar timeOnly = now.toTimeString().slice(0, 8);\n\n\nmsg.topic = \"INSERT INTO rfid_logs (date, time ,LEDorRFID,memo ) VALUES ($dateOnly, $timeOnly ,$LEDorRFID,$memo)\";\nmsg.payload = [dateOnly, timeOnly, LEDorRFID, memo]\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":640,"wires":[["c6538f6c363c5177"]]},{"id":"c6538f6c363c5177","type":"sqlite","z":"448157ebc5541371","mydb":"04085aab75f5ad41","sqlquery":"msg.topic","sql":"","name":"RFID","x":430,"y":640,"wires":[["4077e1c59441a301","062d62b2355724f6"]]},{"id":"4077e1c59441a301","type":"debug","z":"448157ebc5541371","name":"debug ","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":590,"y":640,"wires":[]},{"id":"267b3bad3a0b05c1","type":"debug","z":"448157ebc5541371","name":"debug ","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":590,"y":700,"wires":[]},{"id":"640e917b338f3959","type":"sqlite","z":"448157ebc5541371","mydb":"04085aab75f5ad41","sqlquery":"msg.topic","sql":"","name":"RFID","x":450,"y":700,"wires":[["267b3bad3a0b05c1","062d62b2355724f6"]]},{"id":"b8ff3277ea021729","type":"ui_button","z":"448157ebc5541371","name":"刪除一筆","group":"729b8cad8d9aa5ca","order":6,"width":3,"height":1,"passthru":false,"label":"刪除一筆","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"","topicType":"str","x":80,"y":700,"wires":[["ccec8a03b3ed4d2e"]]},{"id":"1223aa8e351649aa","type":"ui_button","z":"448157ebc5541371","name":"顯示最新50筆","group":"729b8cad8d9aa5ca","order":3,"width":3,"height":1,"passthru":false,"label":"顯示全部設定","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"","topicType":"str","x":100,"y":780,"wires":[["062d62b2355724f6"]]},{"id":"062d62b2355724f6","type":"function","z":"448157ebc5541371","name":"組合顯示所有SQL","func":"\nmsg.topic = \"SELECT id, date, time, LEDorRFID, memo FROM rfid_logs ORDER BY id DESC LIMIT 50\";\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":780,"wires":[["a100deb0624e7c6b"]]},{"id":"1184a6ff8873cab5","type":"ui_table","z":"448157ebc5541371","group":"729b8cad8d9aa5ca","name":"設定資料表","order":7,"width":9,"height":9,"columns":[{"field":"id","title":"ID","width":"15%","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"date","title":"星期","width":"20%","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"time","title":"時間","width":"20%","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"LEDorRFID","title":"LED或RFID","width":"30%","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"memo","title":"備註","width":"30%","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}}],"outputs":0,"cts":false,"x":730,"y":780,"wires":[]},{"id":"9d44b2fe693cc821","type":"ui_dropdown","z":"448157ebc5541371","name":"模式選擇","label":"控制模式","tooltip":"","place":"","group":"5ed27e92f756bcf4","order":4,"width":6,"height":1,"passthru":true,"multiple":false,"options":[{"label":"新增","value":"create","type":"str"},{"label":"比對","value":"verify","type":"str"}],"payload":"","topic":"mode","topicType":"str","className":"","x":80,"y":840,"wires":[["104303cbaa7163f4"]]},{"id":"104303cbaa7163f4","type":"function","z":"448157ebc5541371","name":"暫存模式","func":"flow.set('mode', msg.payload);\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":840,"wires":[["6a18874cf8db9321"]]},{"id":"6a18874cf8db9321","type":"debug","z":"448157ebc5541371","name":"debug  ","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":410,"y":840,"wires":[]},{"id":"61290d7a37f46f8a","type":"inject","z":"448157ebc5541371","name":"建立資料庫","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":900,"wires":[["db16ac459547969f"]]},{"id":"db16ac459547969f","type":"function","z":"448157ebc5541371","name":"建立資料庫 SQL","func":"msg.topic = `CREATE TABLE IF NOT EXISTS rfid_logs (   id INTEGER PRIMARY KEY AUTOINCREMENT,  \n                date TEXT NOT NULL,\n                time TEXT NOT NULL,\n                LEDorRFID TEXT,\n                memo TEXT )`;\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":900,"wires":[["75209616c5b3e25c"]]},{"id":"75209616c5b3e25c","type":"sqlite","z":"448157ebc5541371","mydb":"04085aab75f5ad41","sqlquery":"msg.topic","sql":"","name":"RFID","x":430,"y":900,"wires":[["996edd23a89ff222"]]},{"id":"996edd23a89ff222","type":"debug","z":"448157ebc5541371","name":"debug  ","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":550,"y":900,"wires":[]},{"id":"a4700ec6830e4740","type":"ui_button","z":"448157ebc5541371","name":"建立資料庫","group":"729b8cad8d9aa5ca","order":1,"width":3,"height":1,"passthru":false,"label":"建立資料庫","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"","topicType":"str","x":90,"y":940,"wires":[["db16ac459547969f"]]},{"id":"0b06ebd430fedead","type":"ui_button","z":"448157ebc5541371","name":"查詢一筆","group":"729b8cad8d9aa5ca","order":5,"width":3,"height":1,"passthru":false,"label":"查詢一筆","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"","topicType":"str","x":80,"y":560,"wires":[["22050570edbba3d8"]]},{"id":"22050570edbba3d8","type":"function","z":"448157ebc5541371","name":"組合查詢一筆 SQL","func":"var id = flow.get('delete_id') || msg.payload;\nif(!id) return null;\nmsg.topic = `SELECT id, date, time, LEDorRFID, memo FROM rfid_logs  WHERE id= $id`;\nmsg.payload = [id];\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":560,"wires":[["8f85e8703e7b2348"]]},{"id":"8f85e8703e7b2348","type":"sqlite","z":"448157ebc5541371","mydb":"04085aab75f5ad41","sqlquery":"msg.topic","sql":"","name":"RFID","x":430,"y":560,"wires":[["1184a6ff8873cab5"]]},{"id":"8111ca8ecf61f32d","type":"mqtt in","z":"448157ebc5541371","name":"ledStatus","topic":"alex9ufo/rfid/ledStatus","qos":"1","datatype":"auto-detect","broker":"e93144c18f3d6409","nl":false,"rap":true,"rh":0,"inputs":0,"x":80,"y":640,"wires":[["717f1b8d1458c3d6"]]},{"id":"4035c5171ccf55a1","type":"function","z":"448157ebc5541371","name":"function   flow.set","func":"var idno =msg.payload;\nflow.set('delete_id',idno)\nmsg.payload= idno;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":500,"wires":[["5f9fe616a7cef33e"]]},{"id":"da635fbb00a8997c","type":"ui_button","z":"448157ebc5541371","name":"刪除資料庫","group":"729b8cad8d9aa5ca","order":2,"width":3,"height":1,"passthru":false,"label":"刪除資料庫","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"","topicType":"str","x":90,"y":980,"wires":[["ca9c2e1244cf72f3"]]},{"id":"ca9c2e1244cf72f3","type":"function","z":"448157ebc5541371","name":"刪除資料庫 SQL","func":"msg.topic = `DROP TABLE IF EXISTS rfid_logs`;\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":980,"wires":[["75209616c5b3e25c"]]},{"id":"5f9fe616a7cef33e","type":"debug","z":"448157ebc5541371","name":"debug 368","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":450,"y":500,"wires":[]},{"id":"bfca293065dbd0c9","type":"ui_numeric","z":"448157ebc5541371","name":"","label":"ID","tooltip":"","group":"729b8cad8d9aa5ca","order":4,"width":3,"height":1,"wrap":false,"passthru":true,"topic":"topic","topicType":"msg","format":"{{value}}","min":0,"max":"999999","step":1,"className":"","x":70,"y":500,"wires":[["4035c5171ccf55a1"]]},{"id":"85be98c91e459c6f","type":"telegram sender","z":"448157ebc5541371","name":"","bot":"457874f8aa8a857a","haserroroutput":false,"outputs":1,"x":1010,"y":1180,"wires":[[]]},{"id":"9e6f82181faf4bba","type":"inject","z":"448157ebc5541371","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":1180,"wires":[["322c7cefeb6da2ef"]]},{"id":"256f3431cc5d9a01","type":"template","z":"448157ebc5541371","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"chatId\": 7965218469,\n\"type\":\"message\",\n\"content\":\"{{payload}}\",\n\"Parse Mode\": \"Markdown\"}","output":"json","x":810,"y":1180,"wires":[["85be98c91e459c6f"]]},{"id":"322c7cefeb6da2ef","type":"function","z":"448157ebc5541371","name":"啟動時發送 Help 訊息給Telegram","func":"msg.payload = `啟動時發送 Help 訊息給 Telegram\n🎉 程式已啟動!\n\n可用命令:\n\\\\/on - 開啟 LED (綠色)\n\\\\/off - 關閉 LED (紅色)\n\\\\/flash - LED 閃爍 (紅綠交替)\n\\\\/timer - LED 開啟 10 秒後自動關閉\n\\\\/mode - 切換模式 (新增/比對)\n\\\\/status - 顯示當前模式及最新記錄`;\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":1180,"wires":[["256f3431cc5d9a01"]]},{"id":"22dbd6f0dba2137a","type":"mqtt in","z":"448157ebc5541371","name":"","topic":"alex9ufo/rfid/UID","qos":"1","datatype":"auto-detect","broker":"e93144c18f3d6409","nl":false,"rap":true,"rh":0,"inputs":0,"x":100,"y":1100,"wires":[["be52afa039a5e931","f94d2439fd60b7d7"]]},{"id":"be52afa039a5e931","type":"function","z":"448157ebc5541371","name":"[新增]卡號號碼","func":"var mode = flow.get('mode');\nflow.set('uid', msg.payload);\nvar uid=msg.payload;\nif (mode=='create'){\n    msg.payload= '[新增]卡號號碼'+ uid;\n    return msg;\n}\nreturn null;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":1100,"wires":[["256f3431cc5d9a01","5eab10d3417ccc67","51bd7abf40e987f8"]]},{"id":"f1436aa08fb9f73e","type":"sqlite","z":"448157ebc5541371","mydb":"04085aab75f5ad41","sqlquery":"msg.topic","sql":"","name":"RFID","x":690,"y":1100,"wires":[["c6f6859106efe540"]]},{"id":"5eab10d3417ccc67","type":"function","z":"448157ebc5541371","name":"組合新增 SQL","func":"var memo, LEDorRFID ;\nLEDorRFID = flow.get('uid');\nmemo =msg.payload;\n\n// 建立一個 Date 物件,它包含運行 Node-RED 的電腦的當前時間\nvar now = new Date();\n// --- 提取日期時間的不同格式 ---\n// 1. 完整的 ISO 格式 (例如: 2025-10-25T03:28:08.500Z)\nvar isoString = now.toISOString();\n\n// 2. YYYY-MM-DD (日期部分)\n// slice(0, 10) 會擷取 ISO 字串的前 10 個字元\nvar dateOnly = now.toISOString().slice(0, 10); \n\n// 3. HH:MM:SS (時間部分)\n// toTimeString() 輸出類似 \"11:28:08 GMT+0800 (CST)\" 的字串\n// slice(0, 8) 會擷取開頭的 HH:MM:SS\nvar timeOnly = now.toTimeString().slice(0, 8);\n\n\nmsg.topic = \"INSERT INTO rfid_logs (date, time ,LEDorRFID,memo ) VALUES ($dateOnly, $timeOnly ,$LEDorRFID,$memo)\";\nmsg.payload = [dateOnly, timeOnly, LEDorRFID, memo]\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":500,"y":1100,"wires":[["f1436aa08fb9f73e"]]},{"id":"c6f6859106efe540","type":"link out","z":"448157ebc5541371","name":"link out 78","mode":"link","links":["0a89297ad75019f9"],"x":795,"y":1100,"wires":[]},{"id":"0a89297ad75019f9","type":"link in","z":"448157ebc5541371","name":"link in 72","links":["c6f6859106efe540"],"x":235,"y":800,"wires":[["062d62b2355724f6"]]},{"id":"51bd7abf40e987f8","type":"ui_text","z":"448157ebc5541371","group":"5ed27e92f756bcf4","order":5,"width":0,"height":0,"name":"","label":"","format":"{{msg.payload}}","layout":"row-left","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":470,"y":1060,"wires":[]},{"id":"b8a8f3e9e8dc1b42","type":"inject","z":"448157ebc5541371","name":"查詢所有 UID","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":110,"y":1300,"wires":[["f94d2439fd60b7d7"]]},{"id":"f94d2439fd60b7d7","type":"function","z":"448157ebc5541371","name":"建立 SQL 查詢","func":"// Function Name: Get All Stored UIDs Query Generator\nvar mode = flow.get('mode');\nvar uid = msg.payload;\nflow.set('uid', msg.payload);\n\nif (mode == 'verify') {\n    msg.topic = \"SELECT * FROM rfid_logs WHERE LEDorRFID = $uid LIMIT 1\";\n    msg.payload = [uid]\n}\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":1300,"wires":[["6e0a917b63964b1e"]]},{"id":"6e0a917b63964b1e","type":"sqlite","z":"448157ebc5541371","mydb":"04085aab75f5ad41","sqlquery":"msg.topic","sql":"","name":"查詢 rfid_logs","x":480,"y":1300,"wires":[["9052d8c7127959db","d245523071a2381a"]]},{"id":"a41300479afbd0a2","type":"debug","z":"448157ebc5541371","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":790,"y":1380,"wires":[]},{"id":"1b225619fab2f4db","type":"ui_text","z":"448157ebc5541371","group":"5ed27e92f756bcf4","order":5,"width":0,"height":0,"name":"","label":"","format":"{{msg.payload}}","layout":"row-left","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":1050,"y":1240,"wires":[]},{"id":"9052d8c7127959db","type":"function","z":"448157ebc5541371","name":"(Result Processor)","func":"// Function Name: Convert DB Results to UID List\n\nvar dbResults = msg.payload;\nvar uidList = [];\n\nif (Array.isArray(dbResults)) {\n    // 遍歷結果陣列,提取每個物件的 LEDorRFID 值\n    uidList = dbResults.map(function (row) {\n        // 確保 row[0] 或 row.LEDorRFID 存在\n        if (row && row.LEDorRFID !== undefined) {\n            return row.LEDorRFID;\n        }\n        return null;\n    }).filter(function (uid) {\n        // 過濾掉 null 值 (雖然在 SQL 查詢中 LEDorRFID 應該不會是 NULL)\n        return uid !== null;\n    });\n} else {\n    // 處理非預期的錯誤\n    node.error(\"SQLite node did not return an array. Check DB connection.\", msg);\n    // 返回空列表\n    uidList = [];\n}\n\n// 將轉換後的 UID 列表存入 msg.payload\nmsg.payload = uidList;\n\n// 可以在 msg.status 中儲存操作狀態 (模擬 Python 的 True, results)\nmsg.status = (Array.isArray(dbResults));\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":1300,"wires":[["a41300479afbd0a2","02d3a50734c8ba53"]]},{"id":"02d3a50734c8ba53","type":"function","z":"448157ebc5541371","name":"Status Checker","func":"// Function Name: Status Checker and Formatter (已修正)\n// 假設要比對的 UID 儲存在 msg.uid 中\n\nvar dbResults = msg.payload;\nvar outputUid = flow.get('uid');\n// 1. 檢查 msg.payload 是否為非空陣列\nif (Array.isArray(dbResults) && dbResults.length > 0) {\n    // 成功:找到至少一筆匹配的記錄\n    msg.payload = '比對正確 卡號:' + outputUid;\n\n    // 輸出到第一個埠 (Port 1: 成功)\n    return [msg, null]; \n    \n} else {\n    // 失敗:未找到匹配的記錄 (msg.payload 為空陣列或其他非陣列/空值)\n    \n    msg.payload = '比對錯誤';\n\n    // 輸出到第二個埠 (Port 2: 錯誤)\n    // 如果 Function 節點只有一個輸出埠,請使用 return [msg];\n    return [null, msg]; \n}\n\n// 注意:請確保此 Function 節點有兩個輸出埠 (Port 1 和 Port 2)","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":1280,"wires":[["1b225619fab2f4db","256f3431cc5d9a01"],["1b225619fab2f4db","256f3431cc5d9a01"]]},{"id":"d245523071a2381a","type":"debug","z":"448157ebc5541371","name":"debug  ","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":650,"y":1260,"wires":[]},{"id":"457874f8aa8a857a","type":"telegram bot","botname":"@alextest999_bot","usernames":"","chatids":"7965218469","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":"e93144c18f3d6409","type":"mqtt-broker","name":"HiveMQ","broker":"broker.hivemq.com","port":"1883","tls":"","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"5ed27e92f756bcf4","type":"ui_group","name":"控制台","tab":"955b4de83b0e88a3","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"04085aab75f5ad41","type":"sqlitedb","db":"rfid_node-red.db","mode":"RWC"},{"id":"729b8cad8d9aa5ca","type":"ui_group","name":"資料表","tab":"955b4de83b0e88a3","order":2,"disp":true,"width":9,"collapse":false,"className":""},{"id":"955b4de83b0e88a3","type":"ui_tab","name":"RFID 控制","icon":"dashboard","order":1}]

沒有留言:

張貼留言

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...