2023年12月19日 星期二

實習 2-1 , 2-2 ,2-3 Arduino 程式說明2

 

實習 2-1 , 2-2 ,2-3 Arduino 程式說明2

 



//wifi &  MQTT

#include <WiFi.h>             //定義Wifi 程式庫

#include <PubSubClient.h>      //定義MQTT Pub發行 Sub 訂閱 程式庫

 

//RC522 SPI Mode

#include <SPI.h>              //定義MFRC522 RFID read ESP32 介面

#include <MFRC522.h>          //定義MFRC522 RFID read程式庫

 

 

//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     Arduino       Arduino   Arduino    Arduino          Arduino

 *             Reader/PCD             Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro

 * Signal      Pin          Pin       Pin           Pin       Pin        Pin              Pin

 * -----------------------------------------------------------------------------------------

 * RST/Reset   RST          GPIO27    9             5         D9         RESET/ICSP-5     RST

 * SPI SS      SDA(SS)      GPIO5     10            53        D10        10               10

 * SPI MOSI    MOSI         GPIO23    11 / ICSP-4   51        D11        ICSP-4           16

 * SPI MISO    MISO         GPIO19    12 / ICSP-1   50        D12        ICSP-1           14

 * SPI SCK     SCK          GPIO18    13 / ICSP-3   52        D13        ICSP-3           15

 *

[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

=============================================================================

*/

 

 

#define SS_PIN  5  // ESP32 pin GIOP5 //MFRC522 SS接腳 與 ESP32 的連接Pin

#define RST_PIN 27 // ESP32 pin GIOP27    //MFRC522 RST接腳 與 ESP32 的連接Pin



// WiFi SSID password , SSID 和密碼進行Wi-Fi 設定 

const char *ssid = "alex9ufo"; // Enter your Wi-Fi name

const char *password = "alex9981";  // Enter Wi-Fi password

 

// MQTT Broker伺服器名稱 使用者名稱 密碼 發行主題 訂閱主題的定義

const char *mqtt_broker = "broker.mqtt-dashboard.com";

const char *topic1 = "alex9ufo/esp32/led";

const char *topic2 = "alex9ufo/esp32/RFID";

const char *topic = "alex9ufo/esp32/Starting";

const char *topic3 = "alex9ufo/esp32/led_status";

 

const char *mqtt_username = "alex9ufo";

const char *mqtt_password = "public";

const int mqtt_port = 1883;

 

//布林代數 LED狀態 是否連上網路ESP32 ready ?

bool ledState = false;

bool atwork = false;


//
定義WiFiClient 別名
//PubSubClient 物件名稱(網路用戶端物件)  
//初始化MFRC522

WiFiClient espClient;

PubSubClient client(espClient);

MFRC522 rfid(SS_PIN, RST_PIN); // Create MFRC522 instance

 

//定義long 變數

long lastMsg = 0;

long lastMsg1= 0;

 

//定義 MQTT 發行及訂閱需要的變數

char msg[50];

String json = "";

bool Flash = false;  //true

bool Timer = false;  //true

bool Send = false;  //true

int Count= 0;

 

//定義 MQTT 發行及訂閱需要的變數

char jsonChar1[50];  //client.publish("alex9ufo/Esp32/RFID"

//宣告任務Task1

TaskHandle_t Task1;

 

// Wifi reconnect 重新連線需要的變數

unsigned long previousMillis = 0;

unsigned long interval = 30000;

//===========================================================

//任務1副程式Task1_senddata

 

//由於ESP32有著240/160MHz的雙核心CPU

//一般我們的程式都僅在ESP32的核心1執行(核心編號1),

//所以根本沒用到第二個核心(核心編號0

 

void Task1_senddata(void * pvParameters ) {

 //無窮迴圈

  for (;;) {

    //偵測上傳旗標是否為true

    Serial.println("Reading RFID tag");

    if (rfid.PICC_IsNewCardPresent()) { // new tag is available

      if (rfid.PICC_ReadCardSerial()) { // NUID has been readed

        MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);

        Serial.print("RFID/NFC Tag Type: ");

        Serial.println(rfid.PICC_GetTypeName(piccType));

        String rfidno="";

        // print UID in Serial Monitor in the hex format

        Serial.print("UID:");

        for (int i = 0; i < rfid.uid.size; i++) {

          Serial.print(rfid.uid.uidByte[i] < 0x10 ? " 0" : " ");

          Serial.print(rfid.uid.uidByte[i], HEX);

        }

        Serial.println(); 

 

        String json = printHex(rfid.uid.uidByte, rfid.uid.size);

        json.trim();

        json.toUpperCase();

        // Convert JSON string to character array

        json.toCharArray(jsonChar1, json.length()+1);

   

        if  (client.connected()) {

            Serial.print("Publish message: ");

            Serial.println(json);

            // Publish JSON character array to MQTT topic

            client.publish(topic2,jsonChar1);

             

          rfid.PICC_HaltA(); // halt PICC

          rfid.PCD_StopCrypto1(); // stop encryption on PCD

        }  

        else

        {

          Serial.print("MQTT not connected ");

        }

     

      }

    }



    else  

    {

      // PN532 probably timed out waiting for a card

      Serial.println("Timed out waiting for a card");

    }      

    //Task1休息,delay(X)不可省略

    delay(1000);

  }

}

//===========================================================

//副程式 UID No. in the hex format

//===========================================================

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, 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);

    Serial.print("Message: ");

    String message;

   //將接收資料轉成字串以利後續判斷

    for (int i = 0; i < length; i++) {

        message += (char) payload[i];  // Convert *byte to string

    }

    Serial.print(message); 

   //判斷是否為 on , off , toggle , flash , timer

    if (message == "on" && !ledState) {

        digitalWrite(LED, HIGH);  // Turn on the LED

        ledState = true;  //ledState = ture HIGH

       //設定 各個 旗號

        Flash = false;

        Timer = false;

        json ="ON";

        Send = true ;

    }

    if (message == "off" && ledState) {

        digitalWrite(LED, LOW); // Turn off the LED

        ledState = false; //ledState = false LOW

        Flash = false;

        Timer = false;

        json ="OFF";

        Send = true ;

 

    }

    if (message == "flash" ) {

        digitalWrite(LED, LOW); // Turn off the LED

        Flash = true;

        Timer = false;

        json ="FLASH";

        Send = true ;        

 

    }

    if (message == "timer" ) {

        digitalWrite(LED, LOW); // Turn off the LED

        Flash = false;

        Timer = true;

        json ="TIMER";

        Send = true ;

        Count= 11;

    }

 

    if (message == "toggle" ) {

        digitalWrite(LED, !digitalRead(LED));   // Turn the LED toggle

        if (digitalRead(LED))

            ledState = true;

        else

            ledState = false;

       

        Flash = false;

        Timer = false;

        json ="TOGGLE";

        Send = true ;        

    }

 

    Serial.println();

    Serial.println("-----------------------");

}

//===========================================================

//  若目前沒有和伺服器相連,則反覆執行直到連結成功

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/esp32/led");

      client.subscribe("alex9ufo/esp32/RFID");      

    } 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();

      }

    }

  }

}

//===========================================================

//判斷 旗號Flash , Timer 是否為真

void LED_Message() {

    if (Flash){

        digitalWrite(LED, !digitalRead(LED));

        delay(500);

        if (digitalRead(LED))

            ledState = true;

        else

            ledState = false;

    } //(Flash)

       

    if (Timer) {

        digitalWrite(LED, HIGH);

        delay(500);

        if (digitalRead(LED))

            ledState = true;

        else

            ledState = false;

 

        Count=Count-1;

        if (Count == 0 ){

            Timer=false;

            digitalWrite(LED, LOW);

            ledState = false;

        }

    } //(Timer)

   

   ////判斷 旗號 Send 是否為真 回傳MQTT訊息到MQTT Broker 

    if (client.connected()) {        

        if (Send) {

          // Convert JSON string to character array

          json.toCharArray(jsonChar1, json.length()+1);

          Serial.print("Publish message: ");

          Serial.println(json);

          // Publish JSON character array to MQTT topic

          client.publish(topic3,jsonChar1);

        }

        Send = false;    //處理過後 旗號 Send為假

    }

    else

    {

      if (WiFi.status() != WL_CONNECTED)  {

        Serial.println("Reconnecting to WiFi...");

        WiFi.disconnect();

        WiFi.reconnect();

      }

    }

 

}

 

//===========================================================

//setup()這個函式只會執行大括號裡面的程式一遍, 主要就是在Arduino一開機後,//將所有初始該設置的東西先設置好

 

void setup() {

    // Set software serial baud to 115200;

    Serial.begin(115200);

    delay(1000); // Delay for stability

    //======================================================

    // Connecting to a WiFi network

    setup_wifi();

    // Setting LED pin as output

    pinMode(LED, OUTPUT);

    digitalWrite(LED, LOW);  // Turn off the LED initially

    //======================================================

    SPI.begin();           // Init SPI bus

    rfid.PCD_Init();       // Init MFRC522

 

    Serial.println(F("Ready!"));

    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);

    client.setCallback(callback);

    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.publish(topic,"ESP32 at work");

 

    //在核心0啟動任務1

    xTaskCreatePinnedToCore(

    Task1_senddata,   /*任務實際對應的Function*/

      "Task1",        /*任務名稱*/

      10000,          /*堆疊空間*/

      NULL,           /*無輸入值*/

      0,              /*優先序0*/

      &Task1,         /*對應的任務變數位址*/

      0);             /*指定在核心0執行 */

}

//===========================================================

//重複循環執行你所寫入loop()內的程式碼

void loop()

{

 if (!client.connected()) { //假設未連接的處理程序

      reconnect();

      Serial.print(" client not connected  reconnect ");

      delay(200);

    } 

  client.loop();

  // Process LED message

  LED_Message();

 

  unsigned long currentMillis = millis();

  // if WiFi is down, try reconnecting

  if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {

    Serial.print(millis());

    Serial.println("Reconnecting to WiFi...");

    WiFi.disconnect();

    WiFi.reconnect();

    previousMillis = currentMillis;

 

    client.setCallback(callback);

  }

 

}

//===========================================================

 

沒有留言:

張貼留言

Messaging API作為替代方案

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