#include <ArduinoMqttClient.h>
#include <WiFi.h>
//MFRC522 程式庫 模擬mfrc522 送出卡號 PB可以控制
int LED1 = 23;
int LED2 = 22;
int LED3 = 21;
int LED4 = 19;
char ssid[]="Wokwi-GUEST";
char pass[]="";
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
//const char broker[] = "test.mosquitto.org";
const char broker[] = "broker.mqttgo.io";
//const char broker[] = "broker.mqtt-dashboard.com";
int port = 1883;
const char *SubTopic1 = "alex9ufo/esp32/led";
const char *PubTopic2 = "alex9ufo/esp32/led_status";
const char *PubTopic3 = "alex9ufo/esp32/RFID";
const char willTopic[] = "alex9ufo/esp32/Starting";
int inPin = 12; // pushbutton connected to digital pin 7
int val = 0; // variable to store the read value
bool create=false;
bool Send = false; //true
bool Flash1 = false; //true
bool Flash2 = false; //true
bool Flash3 = false; //true
bool Flash4 = false; //true
String LEDjson = "";
//===========================================================
void onMqttMessage(int messageSize) {
// we received a message, print out the topic and contents
Serial.print("Received a message with topic '");
Serial.print(mqttClient.messageTopic());
String Topic= mqttClient.messageTopic();
Serial.print("', duplicate = ");
Serial.print(mqttClient.messageDup() ? "true" : "false");
Serial.print(", QoS = ");
Serial.print(mqttClient.messageQoS());
Serial.print(", retained = ");
Serial.print(mqttClient.messageRetain() ? "true" : "false");
Serial.print("', length ");
Serial.print(messageSize);
Serial.println(" bytes:");
String message="";
// use the Stream interface to print the contents
while (mqttClient.available()) {
//Serial.print((char)mqttClient.read());
message += (char)mqttClient.read();
}
Serial.println(message);
message.trim();
Topic.trim();
if (Topic=="alex9ufo/esp32/led") {
if (message == "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 (message == "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 (message == "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 (message == "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 (message == "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 (message == "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 (message == "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 (message == "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 (message == "led1flash" ) {
digitalWrite(LED1, HIGH); // Turn off the LED
Flash1 = true;
//Flash2 = false;
//Flash3 = false;
//Flash4 = false;
LEDjson ="LED1FLASH";
Send = true ;
Serial.println(LEDjson);
}
if (message == "led2flash" ) {
digitalWrite(LED2, HIGH); // Turn off the LED
Flash2 = true;
//Flash1 = false;
//Flash3 = false;
//Flash4 = false;
LEDjson ="LED2FLASH";
Send = true ;
Serial.println(LEDjson);
}
if (message == "led3flash" ) {
digitalWrite(LED3, HIGH); // Turn off the LED
Flash3 = true;
//Flash1 = false;
//Flash2 = false;
//Flash4 = false;
LEDjson ="LED3FLASH";
Send = true ;
Serial.println(LEDjson);
}
if (message == "led4flash" ) {
digitalWrite(LED4, HIGH); // Turn off the LED
Flash4 = true;
//Flash1 = false;
//Flash2 = false;
//Flash3 = false;
LEDjson ="LED4FLASH";
Send = true ;
Serial.println(LEDjson);
}
if (message == "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 (message == "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);
}
Serial.println();
Serial.println("-----------------------");
}
}
//===========================================================
//===========================================================
//判斷 旗號Flash , Timer 是否為真
void LED_Message() {
//判斷 旗號 Flash / timer 是否為真 ? 閃爍 定時
if (Flash1 && Flash2 && Flash3 && Flash4){
digitalWrite(LED1, !digitalRead(LED1));
digitalWrite(LED2, !digitalRead(LED2));
digitalWrite(LED3, !digitalRead(LED3));
digitalWrite(LED4, !digitalRead(LED4));
delay(500);
}
if (Flash1) {
digitalWrite(LED1, !digitalRead(LED1));
delay(500);
} //(Flash1)
if (Flash2){
digitalWrite(LED2, !digitalRead(LED2));
delay(500);
} //(Flash2)
if (Flash3){
digitalWrite(LED3, !digitalRead(LED3));
delay(500);
} //(Flash3)
if (Flash4){
digitalWrite(LED4, !digitalRead(LED4));
delay(500);
} //(Flash4)
////判斷 旗號 Send 是否為真 回傳MQTT訊息到MQTT Broker
if (Send) {
// Convert JSON string to character array
Serial.print("Publish message: ");
Serial.println(LEDjson);
LEDjson.trim();
bool retained = false;
int qos = 1;
bool dup = false;
// Publish JSON character array to MQTT topic
mqttClient.beginMessage(PubTopic2, LEDjson.length(), retained, qos, dup); //LED Status
mqttClient.print(LEDjson);
mqttClient.endMessage();
Send = false; //處理過後 旗號 Send為假
}
}
//===========================================================
//===========================================================
//副程式 setup wifi
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid); //print ssid
WiFi.begin(ssid, pass); //初始化WiFi 函式庫並回傳目前的網路狀態
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
} //假設 wifi 未連接 show ………
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
//==================================================================
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
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
setup_wifi();
Serial.println("You're connected to the network");
Serial.println();
String willPayload = "ESP32 Start working....!";
bool willRetain = true;
int willQos = 1;
mqttClient.beginWill(willTopic, willPayload.length(), willRetain, willQos);
mqttClient.print(willPayload);
mqttClient.endWill();
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
// set the message receive callback
mqttClient.onMessage(onMqttMessage);
Serial.print("Subscribing to topic: ");
Serial.println(SubTopic1);
// subscribe to a topic
// the second parameter sets the QoS of the subscription,
// the the library supports subscribing at QoS 0, 1, or 2
int subscribeQos = 1;
mqttClient.subscribe(SubTopic1, subscribeQos);
Serial.println();
/***
Init SPI bus
Init MFRC522
***/
}
//==================================================================
void loop() {
val = digitalRead(inPin); // read the input pin
if (val==LOW) create= false;
if (val==HIGH) create= true;
// call poll() regularly to allow the library to receive MQTT messages and
// send MQTT keep alives which avoids being disconnected by the broker
mqttClient.poll();
LED_Message();
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();
bool retained = false;
int qos = 1;
bool dup = false;
mqttClient.beginMessage(PubTopic3, json.length(), retained, qos, dup);
mqttClient.print(json);
mqttClient.endMessage();
Serial.println(json);
Serial.println();
}
}
電路圖
4) Node-Red程式
[{"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":40,"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":80,"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":120,"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":160,"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":200,"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":240,"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","4187189e16b0375c"]]},{"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":[["debug1","0a22d4a2657165ad"],["debug2","90d79b4c9d4b0773"],["debug3","fbc38c9011e4c418"],["debug4","69a9a1509ba3e739"],["debug5","d44f7266d3524809"],["debug6","29786589908dd6a7"],["debug7","0d6635a689b7d6b0"],["debug8","1b28cd3697bad642"],["debug9","f4bf4a7b5204983c"],["debug10","d617b4f4b928de16"]]},{"id":"debug1","type":"debug","z":"fcce0e6bead574e7","name":"LED1 ON","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","statusVal":"","statusType":"auto","x":540,"y":40,"wires":[]},{"id":"debug2","type":"debug","z":"fcce0e6bead574e7","name":"LED1 OFF","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":530,"y":120,"wires":[]},{"id":"debug3","type":"debug","z":"fcce0e6bead574e7","name":"LED2 ON","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":520,"y":180,"wires":[]},{"id":"debug4","type":"debug","z":"fcce0e6bead574e7","name":"LED2 OFF","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":530,"y":220,"wires":[]},{"id":"debug5","type":"debug","z":"fcce0e6bead574e7","name":"LED3 ON","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":530,"y":270,"wires":[]},{"id":"debug6","type":"debug","z":"fcce0e6bead574e7","name":"LED3 OFF","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":530,"y":300,"wires":[]},{"id":"debug7","type":"debug","z":"fcce0e6bead574e7","name":"LED4 ON","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":520,"y":340,"wires":[]},{"id":"debug8","type":"debug","z":"fcce0e6bead574e7","name":"LED4 OFF","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":530,"y":380,"wires":[]},{"id":"debug9","type":"debug","z":"fcce0e6bead574e7","name":"ALL ON","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":520,"y":420,"wires":[]},{"id":"debug10","type":"debug","z":"fcce0e6bead574e7","name":"ALL OFF","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":540,"y":520,"wires":[]},{"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":480,"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":440,"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":550,"y":60,"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":550,"y":100,"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":550,"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":200,"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":260,"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":300,"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":340,"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":380,"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":360,"wires":[]},{"id":"f1ab102d6af41123","type":"link out","z":"fcce0e6bead574e7","name":"link out 5","mode":"link","links":["60c56a73fae93760"],"x":725,"y":460,"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":480,"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":480,"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":1160,"y":340,"wires":[["ceaf38b381bc12e0"]]},{"id":"ceaf38b381bc12e0","type":"sqlite","z":"fcce0e6bead574e7","mydb":"f5c97c74cc496505","sqlquery":"msg.topic","sql":"","name":"RFID_2025EX2","x":1340,"y":340,"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":480,"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":340,"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":420,"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":420,"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":420,"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":540,"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":540,"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":540,"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":540,"wires":[["b57e0d922b95bf93"],[]]},{"id":"27477e6cbb0d1ab0","type":"ui_audio","z":"fcce0e6bead574e7","name":"","group":"c1460b15f679e676","voice":"Microsoft Hanhan - Chinese (Traditional, Taiwan)","always":false,"x":1145,"y":440,"wires":[],"l":false},{"id":"8601544629976bf3","type":"link out","z":"fcce0e6bead574e7","name":"link out 14","mode":"link","links":["5673b5e03b67335b"],"x":1745,"y":480,"wires":[]},{"id":"5673b5e03b67335b","type":"link in","z":"fcce0e6bead574e7","name":"link in 17","links":["8601544629976bf3"],"x":1815,"y":480,"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":340,"wires":[["1d13d8d27746f41f","8f883ca3e2e45fba","2175a631874bfc3c","27477e6cbb0d1ab0"]]},{"id":"d75616872c411e2a","type":"sqlite","z":"fcce0e6bead574e7","mydb":"f5c97c74cc496505","sqlquery":"msg.topic","sql":"","name":"RFID_2025EX2","x":1460,"y":420,"wires":[["0125ad9a2c641256"]]},{"id":"a2d7d7399a152e7d","type":"sqlite","z":"fcce0e6bead574e7","mydb":"f5c97c74cc496505","sqlquery":"msg.topic","sql":"","name":"RFID_2025EX2","x":1420,"y":480,"wires":[["ce776f39256a83d6"]]},{"id":"6a6d7897c3cfb419","type":"sqlite","z":"fcce0e6bead574e7","mydb":"f5c97c74cc496505","sqlquery":"msg.topic","sql":"","name":"RFID_2025EX2","x":1760,"y":540,"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":300,"wires":[]},{"id":"4187189e16b0375c","type":"ui_audio","z":"fcce0e6bead574e7","name":"","group":"c1460b15f679e676","voice":"Microsoft Hanhan - Chinese (Traditional, Taiwan)","always":true,"x":105,"y":340,"wires":[],"l":false},{"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":1260,"y":260,"wires":[["2390120793a57c4c"]]},{"id":"feaf4daafd32f27d","type":"comment","z":"fcce0e6bead574e7","name":"LINE Messaging API","info":"","x":1290,"y":220,"wires":[]},{"id":"2390120793a57c4c","type":"function","z":"fcce0e6bead574e7","name":"LINE Messaging API","func":"//CHANNEL_ACCESS_TOKEN = 'Messaging API Token';\nCHANNEL_ACCESS_TOKEN = 'E2ElxCQeoDszSHF0N1TJsyytnnae+HF1XZ733YVYj1RQcpjAT1oi2Fa2TScNbOz+q815fFVp4MuFW+UC4PsfKbvtc/o0OM6hchpxuQURZyvizGq+/cAz/TgCwJ9wQ4ebkQyEXEDzaYUZ/Dx3yaaBgwdB04t89/1O/w1cDnyilFU=';\nUSER_ID = 'Ua2f646d82a75d31dee884a6fdfa95f76'; //'使用者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":1480,"y":260,"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":300,"wires":[["f9cb0f54c0825f98"]]},{"id":"f9cb0f54c0825f98","type":"debug","z":"fcce0e6bead574e7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1930,"y":300,"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":"82f3819207ab5853","type":"ui_tab","name":"WOKWI RFID","icon":"dashboard","order":142,"disabled":false,"hidden":false}]
LINE Developers 說明
Node-Red <<LINE Notify + LINE Developers
SQLite 資料庫的檢視
手機 Line 通知畫面
Node-Red 節點說明
節點圖示
|
說明
|
LED控制 Node-red發行到 WOkWI ESP32 的部分
|
|
On Payload: led1on
Off Payload: led1off
On Payload: led2on
Off Payload: led2off
On Payload: led3on
Off Payload: led3off
On Payload: led4on
Off Payload: led4off
|
|
Payload : ledallon
Payload : ledalloff
|
|
MQTT out 節點
服務端 : broker.mqttgo.io 埠 : 1883
主題 :alex9ufo/esp32/led
|
LED接收 Node-red訂閱 WOkWI ESP32發行的 部分
|
|
MQTT in 節點
服務端 : broker.mqttgo.io 埠 : 1883
主題 : alex9ufo/esp32/led_status
|
|
LED Dispatcher 功能
輸出要設定10個
// 建立一個陣列來裝每個輸出的訊息,預設都為 null
let outputs =
Array(10).fill(null);
// 根據 payload 決定要送出的輸出端口 (0~9)
switch
(msg.payload) {
case "LED1ON":
outputs[0] = msg;
break;
case "LED1OFF":
outputs[1] = msg;
break;
case "LED2ON":
outputs[2] = msg;
break;
case "LED2OFF":
outputs[3] = msg;
break;
case "LED3ON":
outputs[4] = msg;
break;
case "LED3OFF":
outputs[5] = msg;
break;
case "LED4ON":
outputs[6] = msg;
break;
case "LED4OFF":
outputs[7] = msg;
break;
case "LEDALLON":
outputs[8] = msg;
break;
case "LEDALLOFF":
outputs[9] = msg;
break;
default:
return null;
}
// 回傳包含 10 個輸出的陣列
return outputs;
|
|
LED1ON 功能內程式
if (msg.payload
=== "LED1ON")
{
msg.payload = true;
return msg;
} else {
return null;
}
LED1OFF 功能內程式
if (msg.payload
=== "LED1OFF")
{
msg.payload = false;
return msg;
} else {
return null;
}
其餘依此列推
if (msg.payload
=== "LEDALLON")
{
msg.payload = true;
return msg;
} else {
return null;
}
if (msg.payload
=== "LEDALLOFF")
{
msg.payload = false;
return msg;
} else {
return null;
}
|
|
設定顏色
true: green
false: red
|
RFID 資料庫 與 Line Message API 部分 訂閱WOKWI 模擬RFID送出UID碼 暨 發出Line通知
|
|
MQTT in 節點
服務端 : broker.mqttgo.io 埠 : 1883
主題 : alex9ufo/esp32/RFID
|
|
增加 日期 時間 功能程式
var Today = new Date();
var yyyy = Today.getFullYear(); //年
var MM = Today.getMonth()+1; //月
var dd = Today.getDate(); //日
var h = Today.getHours(); //時
var m = Today.getMinutes(); //分
var s = Today.getSeconds(); //秒
if(MM<10)
{
MM =
'0'+MM;
}
if(dd<10)
{
dd =
'0'+dd;
}
if(h<10)
{
h =
'0'+h;
}
if(m<10)
{
m =
'0' + m;
}
if(s<10)
{
s =
'0' + s;
}
var var_date = yyyy+'/'+MM+'/'+dd;
var var_time = h+':'+m+':'+s;
var myUID = msg.payload.uid;
msg.payload="新增一筆:"+ myUID +", 日期:
"+ var_date +", 時間:"+var_time;
return msg;
|
|
LINE
Messaging API 功能程式
需修成成自己的CHANNEL_ACCESS_TOKEN 與 USER_ID
//CHANNEL_ACCESS_TOKEN
= 'Messaging API Token';
CHANNEL_ACCESS_TOKEN
=
'E2ElxCQeoDszSHF0N1TJsyytnnae+HF1XZ733YVYj1RQcpjAT1oi2Fa2TScNbOz+q815fFVp4MuFW+UC4PsfKbvtc/o0OM6hchpxuQURZyvizGq+/cAz/TgCwJ9wQ4ebkQyEXEDzaYUZ/Dx3yaaBgwdB04t89/1O/w1cDnyilFU=';
USER_ID =
'Ua2f646d82a75d31dee884a6fdfa95f76'; //'使用者ID(不是Line ID)';
var msg1=msg.payload;
message = {
type:'text',
text:'Line Developers傳送的訊息:'+msg1
};
headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
};
payload = {
'to': USER_ID,
'messages': [message]
};
msg.headers = headers;
msg.payload = payload;
return msg;
|
|
http request節點
請求方式 : POST
URL : https://api.line.me/v2/bot/message/push
|

|
新增一筆資料的INSERT功能程式
var Today = new Date();
var yyyy = Today.getFullYear(); //年
var MM = Today.getMonth()+1; //月
var dd = Today.getDate(); //日
var h = Today.getHours(); //時
var m = Today.getMinutes(); //分
var s = Today.getSeconds(); //秒
if(MM<10)
{
MM =
'0'+MM;
}
if(dd<10)
{
dd =
'0'+dd;
}
if(h<10)
{
h =
'0'+h;
}
if(m<10)
{
m =
'0' + m;
}
if(s<10)
{
s =
'0' + s;
}
var var_date = yyyy+'/'+MM+'/'+dd;
var var_time = h+':'+m+':'+s;
var myUID = msg.payload.uid;
msg.topic = "INSERT INTO RFIDUID ( UID ,
Date , Time ) VALUES ($myUID,
$var_date , $var_time ) "
;
msg.payload = [myUID, var_date , var_time ]
return msg;
//INSERT INTO RFIDUID (
//id INTEGER,
//UID TEXT,
//Date DATE,
//Time TIME,
//PRIMARY KEY (id)
//);
|
|
名稱 : RFID_2025EX2
Database : 2025EX2_RFID.db <<Read-Write-Create>>
存放位置 : C:\Users\User\ 2025EX2_RFID.db
(第一次執行node-red 時 要先將 資料庫 C:\Users\User\ 2025EX2_RFID.db 建立 按圖示 <<建立RFID資料庫>>
|
|
檢視資料 節點功能
//INSERT INTO RFIDUID (
//id INTEGER,
//UID TEXT,
//Date DATE,
//Time TIME,
//PRIMARY KEY (id)
//);
//SELECT * FROM RFIDUID ORDER BY id DESC LIMIT 50;
msg.topic = "SELECT * FROM RFIDUID ORDER
BY id DESC LIMIT 50";
return msg;
|
|
CREATE DATABASE
功能節點程式
//CREATE TABLE RFIDUID (
//id INTEGER,
//UID TEXT,
//Date DATE,
//Time TIME,
//PRIMARY KEY (id)
//);
//CREATE TABLE LEDSTATUS (id INTEGER,UID
TEXT,Date DATE,Time TIME,PRIMARY KEY (id));
msg.topic = "CREATE TABLE RFIDUID (id
INTEGER,UID TEXT,Date DATE,Time TIME,PRIMARY KEY (id))";
return msg;
|
|
DELETE ALL DATA功能節點程式
//CREATE TABLE RFIDUID (
//id INTEGER,
//UID TEXT,
//Date DATE,
//Time TIME,
//PRIMARY KEY (id)
//);
//CREATE TABLE LEDSTATUS (id INTEGER,UID
TEXT,Date DATE,Time TIME,PRIMARY KEY (id));
msg.topic = "DELETE from RFIDUID";
return msg;
|