2024年2月17日 星期六

ES32 + MFRC522 RFID + MQTT + Node-Red

 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}]

沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...