ES32 + MFRC522 RFID + MQTT + Node-Red
Arduino 程式
需要一個檔案:arduino_secrets.h 內容如下
#define SECRET_SSID ""
#define SECRET_PASS ""
//定義MFRC522 RFID read 與 ESP32 介面 接腳連接Pin assign
/* Wiring RFID RC522 module
==============================================================
GND = GND 3.3V = 3.3V
The following table shows the typical pin layout used:
* MFRC522 ESP32
* Reader/PCD
* Signal Pin Pin
* -----------------------------------
* RST/Reset RST GPIO27
* SPI SS SDA(SS) GPIO5
* SPI MOSI MOSI GPIO23
* SPI MISO MISO GPIO19
* SPI SCK SCK GPIO18
*
[1] (1, 2) Configurable, typically defined as RST_PIN in sketch/program.
[2] (1, 2) Configurable, typically defined as SS_PIN in sketch/program.
[3] The SDA pin might be labeled SS on some/older MFRC522 boards
=============================================================
*/
// Wifi 與 MQttClient 程式庫
#include <ArduinoMqttClient.h>
#include <WiFi.h>
#include "arduino_secrets.h"
//MFRC522 程式庫
#include <SPI.h>
#include <MFRC522.h>
//GPIO 2 D1 Build in LED
#define LED 13 //定義LED接腳
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
//char ssid[] = "TOTOLINK_A3002MU"; // your network SSID (name)
//char pass[] = "24063173"; // your network password (use for WPA, or use as key for WEP)
// WiFi SSID password , SSID 和密碼進行Wi-Fi 設定
//const char ssid[] = "alex9ufo"; // Enter your Wi-Fi name
//const char pass[] = "alex9981"; // Enter Wi-Fi password
char ssid[] = "dlink-103A"; // your network SSID (name)
char pass[] = "bdcce12882"; // your network password (use for WPA, or use as key for WEP)
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
//const char broker[] = "test.mosquitto.org";
const char broker[] = "broker.mqtt-dashboard.com";
int port = 1883;
String json = "";
const char *SubTopic1 = "alex9ufo/2024/LED_control";
const char *PubTopic2 = "alex9ufo/2024/LED_status";
const char *PubTopic3 = "alex9ufo/2024/RFID_UID";
const char willTopic[] = "alex9ufo/esp32/Starting";
//======================================================
#define RST_PIN 27 // 讀卡機的重置腳位
#define SS_PIN 5 // 晶片選擇腳位
MFRC522 mfrc522(SS_PIN, RST_PIN); // 建立MFRC522物件
MFRC522::MIFARE_Key key; // 儲存金鑰
MFRC522::StatusCode status;
//===========================================================
//布林代數 LED狀態 是否連上網路ESP32 ready ?
bool ledState = false;
bool atwork = false;
bool Send = false; //true
String LEDjson = "";
int Count= 0;
//===========================================================
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/2024/LED_control") {
if (message == "on") {
digitalWrite(LED, LOW); // Turn on the LED
//ledState = true; //ledState = ture HIGH
//設定 各個 旗號
LEDjson ="ON";
Send = true ;
Serial.print("LED =");
Serial.println(LEDjson);
}
if (message == "off" ) {
digitalWrite(LED, HIGH); // Turn off the LED
//ledState = false; //ledState = false LOW
LEDjson ="OFF";
Send = true ;
Serial.print("LED =");
Serial.println(LEDjson);
}
Serial.println();
Serial.println("-----------------------");
}
}
//===========================================================
String printHex(byte *buffer, byte bufferSize) {
String id = "";
for (byte i = 0; i < bufferSize; i++) {
id += buffer[i] < 0x10 ? "0" : "";
id += String(buffer[i], HEX);
id +=" ";
}
return id;
}
//===========================================================
//副程式 setup wifi
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid); //print ssid
WiFi.begin(ssid, pass); //初始化WiFi 函式庫並回傳目前的網路狀態
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
} //假設 wifi 未連接 show ………
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
//===========================================================
//判斷 旗號Flash , Timer 是否為真
void LED_Message() {
////判斷 旗號 Send 是否為真 回傳MQTT訊息到MQTT Broker
if (Send) {
// Convert JSON string to character array
Serial.print("Publish message: ");
Serial.println(LEDjson);
LEDjson.trim();
bool retained = false;
int qos = 1;
bool dup = false;
// Publish JSON character array to MQTT topic
mqttClient.beginMessage(PubTopic2, LEDjson.length(), retained, qos, dup); //LED Status
mqttClient.print(LEDjson);
mqttClient.endMessage();
Send = false; //處理過後 旗號 Send為假
}
}
//===========================================================
void setup() {
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH); // Turn off the LED initially
//Initialize serial and wait for port to open:
Serial.begin(115200); // Initialize serial communications with the PC
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
setup_wifi();
Serial.println("You're connected to the network");
Serial.println();
String willPayload = "ESP32 Start working....!";
bool willRetain = true;
int willQos = 1;
mqttClient.beginWill(willTopic, willPayload.length(), willRetain, willQos);
mqttClient.print(willPayload);
mqttClient.endWill();
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
// set the message receive callback
mqttClient.onMessage(onMqttMessage);
Serial.print("Subscribing to topic: ");
Serial.println(SubTopic1);
// subscribe to a topic
// the second parameter sets the QoS of the subscription,
// the the library supports subscribing at QoS 0, 1, or 2
int subscribeQos = 1;
mqttClient.subscribe(SubTopic1, subscribeQos);
Serial.println();
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
delay(4); // Optional delay. Some board do need more time after init to be ready, see Readme
//mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}
//===========================================================
void loop() {
// call poll() regularly to allow the library to receive MQTT messages and
// send MQTT keep alives which avoids being disconnected by the broker
mqttClient.poll();
LED_Message();
// to avoid having delays in loop, we'll use the strategy from BlinkWithoutDelay
// see: File -> Examples -> 02.Digital -> BlinkWithoutDelay for more info
unsigned long currentMillis = millis();
if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
Serial.println(F("Please scan MIFARE Classic card..."));
// 確認是否有新卡片
byte *id = mfrc522.uid.uidByte; // 取得卡片的UID
byte idSize = mfrc522.uid.size; // 取得UID的長度
String Type;
Serial.print("PICC type: "); // 顯示卡片類型
// 根據卡片回應的SAK值(mfrc522.uid.sak)判斷卡片類型
MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Type= mfrc522.PICC_GetTypeName(piccType);
Serial.println(mfrc522.PICC_GetTypeName(piccType));
Serial.print("UID Size: "); // 顯示卡片的UID長度值
Serial.println(idSize);
for (byte i = 0; i < idSize; i++) { // 逐一顯示UID碼
Serial.print("id[");
Serial.print(i);
Serial.print("]: ");
Serial.println(id[i], HEX); // 以16進位顯示UID值
}
Serial.println();
json="";
//json = json +(" Card UID: ");
String json1=printHex(mfrc522.uid.uidByte, mfrc522.uid.size);
json1.toUpperCase();
json = json + json1;
json.trim();
//json = json +(" , PICC type: ");
//json = json + Type;
//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();
// Dump debug info about the card; PICC_HaltA() is automatically called
// 令卡片進入停止狀態
// Dump debug info about the card; PICC_HaltA() is automatically called
// mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1(); // stop encryption on PCD
}
}
////===========================================================
Node-Red 程式
[{"id":"c59686b37b309e43","type":"ui_switch","z":"86b3e6eeb5484ac5","name":"","label":"LED Control switch","tooltip":"","group":"d93d93998de35374","order":14,"width":5,"height":2,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":510,"y":340,"wires":[["cb1ffbab67b58d64","e7ca113edc03d511"]]},{"id":"95af94893f2d6e53","type":"ui_led","z":"86b3e6eeb5484ac5","order":3,"group":"d93d93998de35374","width":6,"height":3,"label":"ESP32 LED Status","labelPlacement":"right","labelAlignment":"center","colorForValue":[{"color":"#ff0000","value":"false","valueType":"bool"},{"color":"#008000","value":"true","valueType":"bool"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":true,"name":"","x":990,"y":240,"wires":[]},{"id":"7a079be5f155366f","type":"ui_text","z":"86b3e6eeb5484ac5","group":"d93d93998de35374","order":1,"width":11,"height":2,"name":"","label":"RFID UID -->","format":"{{msg.payload}}","layout":"row-left","className":"","x":1010,"y":160,"wires":[]},{"id":"67c41933549d0e8b","type":"mqtt out","z":"86b3e6eeb5484ac5","name":"LED_control","topic":"alex9ufo/2024/LED_control","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"603bb104.d6134","x":970,"y":400,"wires":[]},{"id":"a55d82342a298cc4","type":"mqtt in","z":"86b3e6eeb5484ac5","name":"LED_status","topic":"alex9ufo/2024/LED_status","qos":"1","datatype":"auto-detect","broker":"603bb104.d6134","nl":false,"rap":true,"rh":0,"inputs":0,"x":470,"y":240,"wires":[["7173ea47b004a475","72ee320a21953114"]]},{"id":"06443b497f771269","type":"mqtt in","z":"86b3e6eeb5484ac5","name":"RFID_UID","topic":"alex9ufo/2024/RFID_UID","qos":"1","datatype":"auto-detect","broker":"603bb104.d6134","nl":false,"rap":true,"rh":0,"inputs":0,"x":460,"y":160,"wires":[["7a079be5f155366f","64e956d82a770c6b"]]},{"id":"7173ea47b004a475","type":"function","z":"86b3e6eeb5484ac5","name":"function 93","func":"msg.payload = (msg.payload === \"ON\")? true:false;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":240,"wires":[["95af94893f2d6e53","3f9ac8d95ed0645e"]]},{"id":"cb1ffbab67b58d64","type":"function","z":"86b3e6eeb5484ac5","name":"function 94","func":"var a=msg.payload;\nif (a==true)\n msg.payload=\"on\";\nelse\n msg.payload=\"off\"; \n \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":400,"wires":[["67c41933549d0e8b","9b5d7e426f8692ce","17ca9b9e.d2a564"]]},{"id":"e7ca113edc03d511","type":"debug","z":"86b3e6eeb5484ac5","name":"debug 266","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":730,"y":340,"wires":[]},{"id":"72ee320a21953114","type":"debug","z":"86b3e6eeb5484ac5","name":"debug 267","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":730,"y":200,"wires":[]},{"id":"9b5d7e426f8692ce","type":"debug","z":"86b3e6eeb5484ac5","name":"debug 268","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":970,"y":360,"wires":[]},{"id":"e535f7a246f73c7a","type":"ui_button","z":"86b3e6eeb5484ac5","name":"","group":"d93d93998de35374","order":15,"width":3,"height":1,"passthru":false,"label":"ON","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"true","payloadType":"bool","topic":"topic","topicType":"msg","x":550,"y":400,"wires":[["cb1ffbab67b58d64"]]},{"id":"ba5236a0cb5158a5","type":"ui_button","z":"86b3e6eeb5484ac5","name":"","group":"d93d93998de35374","order":16,"width":3,"height":1,"passthru":false,"label":"OFF","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"false","payloadType":"bool","topic":"topic","topicType":"msg","x":550,"y":460,"wires":[["cb1ffbab67b58d64"]]},{"id":"3f9ac8d95ed0645e","type":"debug","z":"86b3e6eeb5484ac5","name":"debug 269","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":970,"y":300,"wires":[]},{"id":"64e956d82a770c6b","type":"delay","z":"86b3e6eeb5484ac5","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":660,"y":120,"wires":[["f4f23a169be7144a"]]},{"id":"f4f23a169be7144a","type":"function","z":"86b3e6eeb5484ac5","name":"function 95","func":"msg.payload=\"\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":830,"y":120,"wires":[["7a079be5f155366f"]]},{"id":"36b481c29223d734","type":"group","z":"86b3e6eeb5484ac5","name":"","style":{"fill":"#ffff00","label":true},"nodes":["17ca9b9e.d2a564","872b1d71.45076","f81160301e1b0e63","c6ac5bac.e91e38","9d39dfc1.aff32"],"x":454,"y":519,"w":592,"h":242},{"id":"17ca9b9e.d2a564","type":"function","z":"86b3e6eeb5484ac5","g":"36b481c29223d734","name":"Test","func":"msg.color = (msg.payload === \"on\")?\"lime\":\"red\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":770,"y":640,"wires":[["872b1d71.45076","f81160301e1b0e63"]]},{"id":"872b1d71.45076","type":"ui_text","z":"86b3e6eeb5484ac5","g":"36b481c29223d734","group":"d93d93998de35374","order":9,"width":3,"height":2,"name":"","label":"LED","format":"<font color={{msg.color}} ><i class=\"fa fa-circle\" style=\"font-size:48px;\"></i></font>","layout":"row-left","className":"","x":970,"y":560,"wires":[]},{"id":"f81160301e1b0e63","type":"ui_template","z":"86b3e6eeb5484ac5","g":"36b481c29223d734","group":"d93d93998de35374","name":"","order":10,"width":3,"height":3,"format":"<svg width=\"120\" height=\"200\">\n <circle id=\"circle1\" cx=\"50\" cy=\"50\" r=\"40\" stroke={{msg.color}} fill=\"transparent\" stroke-width=\"20\"/>\n</svg>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":960,"y":700,"wires":[[]]},{"id":"c6ac5bac.e91e38","type":"inject","z":"86b3e6eeb5484ac5","g":"36b481c29223d734","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"on","payloadType":"str","x":550,"y":560,"wires":[["17ca9b9e.d2a564","7173ea47b004a475"]]},{"id":"9d39dfc1.aff32","type":"inject","z":"86b3e6eeb5484ac5","g":"36b481c29223d734","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"off","payloadType":"str","x":550,"y":720,"wires":[["17ca9b9e.d2a564","7173ea47b004a475"]]},{"id":"d93d93998de35374","type":"ui_group","name":"Group 1 for MQTT","tab":"14f030d69035e0d1","order":1,"disp":true,"width":11,"collapse":false,"className":""},{"id":"603bb104.d6134","type":"mqtt-broker","name":"","broker":"broker.mqtt-dashboard.com","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"15","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"14f030d69035e0d1","type":"ui_tab","name":"Tab for RFID Control","icon":"dashboard","order":101,"disabled":false,"hidden":false}]