ESP32 MFRC522 Read 讀取資料 Sector / Block + Node-Red UI控制 Sector / Block
//wifi & MQTT
#include <WiFi.h> //定義Wifi 程式庫
#include <PubSubClient.h> //定義MQTT Pub發行 Sub 訂閱 程式庫
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 27 // 讀卡機的重置腳位
#define SS_PIN 5 // 晶片選擇腳位
//GPIO 2 D1 Build in LED
#define LED 2 //定義LED接腳
//定義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 SSID password , SSID 和密碼進行Wi-Fi 設定
//const char *ssid = "TOTOLINK_A3002MU"; // Enter your Wi-Fi name
//const char *password = "24063173"; // Enter Wi-Fi password
const char *ssid = "dlink-103A"; // Enter your Wi-Fi name
const char *password = "bdcce12882"; // Enter Wi-Fi password
// MQTT Broker
const char *mqtt_broker = "broker.hivemq.com"; //broker.mqtt-dashboard.com
const char *topic1 = "alex9ufo/RFID/read";
const char *topic3 = "alex9ufo/RFID/back";
const char *mqtt_username = "alex9ufo";
const char *mqtt_password = "public";
const int mqtt_port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
//定義 MQTT 發行及訂閱需要的變數
String json = "";
char jsonChar[50]; //client.publish
bool toggle=false;
bool RD_flag=false;
String text="";
MFRC522 mfrc522(SS_PIN, RST_PIN); // 建立MFRC522物件
MFRC522::MIFARE_Key key; // 儲存金鑰
byte sector = 15; // 指定讀寫的「區段」,可能值:0~15
byte block = 1; // 指定讀寫的「區塊」,可能值:0~3
byte blockData[16] = " "; // 最多可存入16個字元
// 若要清除區塊內容,請寫入16個 0
//byte blockData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// 暫存讀取區塊內容的陣列,MIFARE_Read()方法要求至少要18位元組空間,來存放16位元組。
byte bufferarray[18]=" ";
MFRC522::StatusCode status;
//====================================================
/*** 位元組陣列轉儲為串列的十六進位值
* 這個副程式把讀取到的UID,用16進位顯示出來
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
//===========================================================
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;
}
//===========================================================
void readBlock(byte _sector, byte _block, byte _blockData[]) {
if (_sector < 0 || _sector > 15 || _block < 0 || _block > 3) {
// 顯示「區段或區塊碼錯誤」,然後結束函式。
Serial.println(F("Wrong sector or block number."));
return;
}
byte blockNum = _sector * 4 + _block; // 計算區塊的實際編號(0~63)
byte trailerBlock = _sector * 4 + 3; // 控制區塊編號
// 驗證金鑰
status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
// 若未通過驗證…
if (status != MFRC522::STATUS_OK) {
// 顯示錯誤訊息
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
byte buffersize = 18;
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockNum, _blockData, &buffersize);
// 若讀取不成功…
if (status != MFRC522::STATUS_OK) {
// 顯示錯誤訊息
Serial.print(F("MIFARE_read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
// 顯示「讀取成功!」
Serial.println(F("Data was read."));
}
//===========================================================
//副程式 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, password); //初始化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());
}
//===========================================================
// 接收MQTT主題後呼叫運行程式
//===========================================================
void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
String topic1=topic;
Serial.print("Message: ");
String message;
//將接收資料轉成字串以利後續判斷
for (int i = 0; i < length; i++) {
message += (char) payload[i]; // Convert *byte to string
}
Serial.println(message);
String sec1;
String blk1;
String text1;
toggle = false;
sec1=message.substring(0,2);
blk1=message.substring(3,5);
text=message.substring(6);
sector = sec1.toInt();
block = blk1.toInt();
if (topic1.substring(14,18) == "read") {
String sec1=message.substring(0,2);
String blk1=message.substring(3,5);
//String text1=message.subString(6);
sector = sec1.toInt();
block = blk1.toInt();
Serial.print(sec1);
Serial.print(blk1);
digitalWrite(LED, LOW); // Turn off
toggle=true;
RD_flag=true;
}
}
//===========================================================
// 若目前沒有和伺服器相連,則反覆執行直到連結成功
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("esp32-client-")) {
Serial.println("connected");
// Subscribe
client.subscribe("alex9ufo/RFID/read");
client.subscribe("alex9ufo/RFID/write");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.reconnect();
}
}
}
}
//===========================================================
void setup() {
Serial.begin(115200);
SPI.begin(); // 初始化SPI介面
mfrc522.PCD_Init(); // 初始化MFRC522卡片
//======================================================
// Connecting to a WiFi network
setup_wifi();
// Setting LED pin as output
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW); // Turn off the LED initially
Serial.println(F("Please scan MIFARE Classic card..."));
// 準備金鑰(用於key A和key B),出廠預設為6組 0xFF。
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("============================================="));
Serial.println("Tap an RFID/NFC tag on the RFID-RC522 reader");
// Connecting to an MQTT broker
client.setServer(mqtt_broker, mqtt_port);
while (!client.connected()) {
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("Public HiveMQ MQTT broker (broker.mqtt-dashboard.com) connected");
} else {
Serial.print("Failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// MQTT Publish and subscribe
client.subscribe(topic1);
client.setCallback(callback);
}
//===========================================================
void loop() {
// 查看是否感應到卡片
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// 選取一張卡片
if ( ! mfrc522.PICC_ReadCardSerial()) { // 若傳回1,代表已讀取到卡片的ID
return;
}
digitalWrite(LED, HIGH); // Turn on
if (RD_flag==true) {
if ((sector>0) || (block>0)) {
Serial.print("sector=");
Serial.print(sector,DEC);
Serial.print(", block=");
Serial.println(block,DEC);
readBlock(sector, block, bufferarray); // 區段編號、區塊編號、存放讀取資料的陣列
Serial.print(F("Read block: ")); // 顯示儲存讀取資料的陣列元素值
String str=String((char *)bufferarray);
//for (byte i = 0 ; i <18 ; i++) {
// Serial.write (bufferarray[i]);
//}
Serial.println(str);
//========publish topic3 =========
json = "sector=";
json = json + String(sector);
json = json + ", block=";
json = json + String(block);
json = json + ", Read data : ";
//str=String((char *)bufferarray);
json =json + str;
json.trim();
//json.toCharArray(jsonChar, json.length()+1);
json.toCharArray(jsonChar,20+28+1);
client.publish(topic3,jsonChar);
RD_flag=false;
}
else
{
Serial.print(F("Card UID:"));
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); // 顯示卡片的UID
Serial.println();
Serial.print(F("PICC type: "));
MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Serial.println(mfrc522.PICC_GetTypeName(piccType)); //顯示卡片的類型
json = "sector=";
json = json + String(sector);
json = json + "blockr=";
json = json + String(block);
json =json +(" Card UID: ");
json = json + printHex(mfrc522.uid.uidByte, mfrc522.uid.size);
json.trim();
json = json +(" , PICC type: ");
json = json + String(mfrc522.PICC_GetTypeName(piccType));
json.trim();
//json.toUpperCase();
// Convert JSON string to character array
json.toCharArray(jsonChar, json.length()+1);
client.publish(topic3,jsonChar);
// Dump debug info about the card; PICC_HaltA() is automatically called
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
RD_flag=false;
}
// 令卡片進入停止狀態
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1(); // stop encryption on PCD
} //if (RD_flag==true)
if (!client.connected()) { //假設未連接的處理程序
reconnect();
Serial.print(" client not connected reconnect ");
delay(200);
}
client.loop();
// if WiFi is down, try reconnecting
if (WiFi.status() != WL_CONNECTED) {
Serial.print(millis());
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.reconnect();
client.setCallback(callback);
}
}
//===========================================================
[{"id":"b4fb005ddd98cabd","type":"function","z":"2f5520a7ea5f3ad2","name":"function ","func":"var arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];\nmsg.payload=arr;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":260,"wires":[["072d1871cda8fe10","b7314e689be39f11"]]},{"id":"241a1221cb70b19a","type":"inject","z":"2f5520a7ea5f3ad2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"date","x":160,"y":260,"wires":[["b4fb005ddd98cabd"]]},{"id":"072d1871cda8fe10","type":"debug","z":"2f5520a7ea5f3ad2","name":"debug 257","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":470,"y":260,"wires":[]},{"id":"b7314e689be39f11","type":"change","z":"2f5520a7ea5f3ad2","name":"","rules":[{"t":"set","p":"options","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":220,"wires":[["9c81ed8345cfbe3a"]]},{"id":"9c81ed8345cfbe3a","type":"ui_dropdown","z":"2f5520a7ea5f3ad2","name":"","label":"SECTOR NO:","tooltip":"","place":"Select option","group":"eebf0fc66c6a4d88","order":1,"width":5,"height":1,"passthru":true,"multiple":false,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"topic","topicType":"msg","className":"","x":660,"y":220,"wires":[["91390ae2119ac18a","84531c8ecba4f326"]]},{"id":"91390ae2119ac18a","type":"debug","z":"2f5520a7ea5f3ad2","name":"debug 258","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":810,"y":280,"wires":[]},{"id":"9ae822e79055e3aa","type":"inject","z":"2f5520a7ea5f3ad2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"date","x":160,"y":320,"wires":[["f51c807150d82db5"]]},{"id":"f51c807150d82db5","type":"function","z":"2f5520a7ea5f3ad2","name":"function ","func":"var arr = [0,1,2];\nmsg.payload=arr;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":320,"wires":[["5dcad4e96e4a29ea","beede6ee35ace32e"]]},{"id":"beede6ee35ace32e","type":"change","z":"2f5520a7ea5f3ad2","name":"","rules":[{"t":"set","p":"options","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":360,"wires":[["542cf166f860474d"]]},{"id":"5dcad4e96e4a29ea","type":"debug","z":"2f5520a7ea5f3ad2","name":"debug 259","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":470,"y":320,"wires":[]},{"id":"542cf166f860474d","type":"ui_dropdown","z":"2f5520a7ea5f3ad2","name":"","label":"BLOCK NO:","tooltip":"","place":"Select option","group":"eebf0fc66c6a4d88","order":3,"width":5,"height":1,"passthru":true,"multiple":false,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"topic","topicType":"msg","className":"","x":650,"y":360,"wires":[["8afc0b1d53588863","376a1f319d2a04f8"]]},{"id":"8afc0b1d53588863","type":"debug","z":"2f5520a7ea5f3ad2","name":"debug 260","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":810,"y":420,"wires":[]},{"id":"ca7a327294243506","type":"ui_button","z":"2f5520a7ea5f3ad2","name":"","group":"eebf0fc66c6a4d88","order":5,"width":5,"height":1,"passthru":false,"label":"讀取","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":130,"y":60,"wires":[["5aa783b73c232a7f"]]},{"id":"4b626c8ff4fa0f66","type":"ui_text","z":"2f5520a7ea5f3ad2","group":"eebf0fc66c6a4d88","order":12,"width":"10","height":1,"name":"","label":"ESP回來字串","format":"{{msg.payload}}","layout":"row-spread","className":"","x":380,"y":480,"wires":[]},{"id":"5aa783b73c232a7f","type":"function","z":"2f5520a7ea5f3ad2","name":"function ","func":"var par1 = context.global.sec_no ;\nvar par2 = context.global.blk_no ;\nif(par1<10)\n{\n par1 = '0'+par1;\n}\nif(par2<10)\n{\n par2 = '0'+par2;\n}\nvar par3= par1+','+par2;\n\nmsg.payload=par3;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":60,"wires":[["aa4676b62203ae9a","bff0898877976165"]]},{"id":"84531c8ecba4f326","type":"function","z":"2f5520a7ea5f3ad2","name":"function ","func":"context.global.sec_no=msg.payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":220,"wires":[[]]},{"id":"376a1f319d2a04f8","type":"function","z":"2f5520a7ea5f3ad2","name":"function ","func":"context.global.blk_no=msg.payload;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":360,"wires":[[]]},{"id":"aa4676b62203ae9a","type":"mqtt out","z":"2f5520a7ea5f3ad2","name":"","topic":"alex9ufo/RFID/read","qos":"1","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"841df58d.ee5e98","x":470,"y":60,"wires":[]},{"id":"bd8b284c8c0b817f","type":"mqtt in","z":"2f5520a7ea5f3ad2","name":"","topic":"alex9ufo/RFID/back","qos":"1","datatype":"auto-detect","broker":"841df58d.ee5e98","nl":false,"rap":true,"rh":0,"inputs":0,"x":170,"y":480,"wires":[["4b626c8ff4fa0f66"]]},{"id":"bff0898877976165","type":"debug","z":"2f5520a7ea5f3ad2","name":"debug 261","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":450,"y":120,"wires":[]},{"id":"e8550dbdd8bd1dca","type":"mqtt in","z":"2f5520a7ea5f3ad2","name":"","topic":"alex9ufo/RFID/read","qos":"1","datatype":"auto-detect","broker":"841df58d.ee5e98","nl":false,"rap":true,"rh":0,"inputs":0,"x":170,"y":420,"wires":[["f14e98e117c6bff9"]]},{"id":"f14e98e117c6bff9","type":"ui_text","z":"2f5520a7ea5f3ad2","group":"eebf0fc66c6a4d88","order":10,"width":"10","height":1,"name":"","label":"MQTT 發行的字串","format":"{{msg.payload}}","layout":"row-left","className":"","x":390,"y":420,"wires":[]},{"id":"eebf0fc66c6a4d88","type":"ui_group","name":"RFID SECTOR BLOCK READ","tab":"048debf3dd7e9641","order":2,"disp":true,"width":"10","collapse":false,"className":""},{"id":"841df58d.ee5e98","type":"mqtt-broker","name":"","broker":"broker.hivemq.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":"048debf3dd7e9641","type":"ui_tab","name":"2024 RFID ","icon":"dashboard","disabled":false,"hidden":false}]
沒有留言:
張貼留言