RFID reader

Hi, on Youtube I found an old Blynk project that can add and remove 10 RFID cards in EEPROM instead of hard coding the card numbers.

The current code has a lot going on in the loop, I was going to see if I could get it working and once I understood its function work at cleaning it up. I have the code running and the Blynk LCD display and buttons are working. Meaning when I hit the “unlock” V3 , the display populates. Also the “skip” V2 as well as the “begin” V1. So I am fairly certain that it is not “flooding” at this point. I am successfully running the “dump info” sketch and it looks to me this sketch has the same RFID elements but it is not displaying the card numbers as the video shows. Can someone point me in the right direction?

I should note that I’m using a D1 Mini. Therefore the D reference to pin numbers.

this video…

Working “dump info” code

/*
 * --------------------------------------------------------------------------------------------------------------------
 * Example sketch/program showing how to read data from a PICC to serial.
 * --------------------------------------------------------------------------------------------------------------------
 * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid
 * 
 * Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID
 * Reader on the Arduino SPI interface.
 * 
 * When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE
 * then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When
 * you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output
 * will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages
 * when removing the PICC from reading distance too early.
 * 
 * If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading).
 * So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all
 * details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so
 * keep the PICCs at reading distance until complete.
 * 
 * @license Released into the public domain.
 * 
 * Typical pin layout used:
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 */

#include <SPI.h>
#include <MFRC522.h>

constexpr uint8_t RST_PIN = D3;          // Configurable, see typical pin layout above
constexpr uint8_t SS_PIN = D4;         // Configurable, see typical pin layout above

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

void setup() {
	Serial.begin(9600);		// Initialize serial communications with the PC
	while (!Serial);		// Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
	SPI.begin();			// Init SPI bus
	mfrc522.PCD_Init();		// Init MFRC522
	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() {
	// Look for new cards
	if ( ! mfrc522.PICC_IsNewCardPresent()) {
		return;
	}

	// Select one of the cards
	if ( ! mfrc522.PICC_ReadCardSerial()) {
		return;
	}

	// Dump debug info about the card; PICC_HaltA() is automatically called
	mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
}

Code I’m working with…

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SPI.h>
#include <MFRC522.h>
#include <EEPROM.h>

#define SS_PIN D4
#define RST_PIN D3
#define BTN_PIN D0
#define SLN_PIN D8

MFRC522 mfrc522(SS_PIN, RST_PIN);
unsigned long uidDec, uidDecTemp;
int ARRAYindexUIDcard;
int EEPROMstartAddr;
long adminID = 11;
bool beginCard = 0;
bool addCard = 1;
bool skipCard = 0;
int LockSwitch;
unsigned long CardUIDeEPROMread[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int PiezoPin = D0;

char auth[] = "***";
char ssid[] = "**";
char pass[] = "**";

WidgetLCD lcd(V0);

void setup() {
  //Serial.begin(115200);
  pinMode(SLN_PIN, OUTPUT); digitalWrite(SLN_PIN, LOW);
  pinMode(BTN_PIN, INPUT_PULLUP);
  pinMode(PiezoPin, OUTPUT);
  pinMode(D1, OUTPUT);  //use for ground on piezzo
  digitalWrite(D1,LOW);     //

 
  SPI.begin();
  mfrc522.PCD_Init();
  

  //Serial.println("beforeblynk");
  Blynk.begin(auth, ssid, pass);
  lcd.clear(); //Use it to clear the LCD Widget
  EEPROM.begin(512);
  DisplayWAiT_CARD();
  EEPROMreadUIDcard();

  digitalWrite(PiezoPin, HIGH), delay(100), digitalWrite(PiezoPin, LOW);
  //Serial.println("Setup");

}

void loop() {

  digitalWrite(SLN_PIN, LOW);

  if (digitalRead(BTN_PIN) == HIGH) {
    digitalWrite(SLN_PIN, HIGH); //unlock
    lcd.print(0, 0, " BUTTON UNLOCK ");
    lcd.print(0, 1, "   DOOR OPEN   ");
    digitalWrite(PiezoPin, HIGH), delay(200), digitalWrite(PiezoPin, LOW);
    delay(2000);
    DisplayWAiT_CARD();
  }

  if (beginCard == 0) { //0
    if ( ! mfrc522.PICC_IsNewCardPresent()) {  //Look for new cards.
      //Serial.println("not new card");
      Blynk.run();
      return;
    }

    if ( ! mfrc522.PICC_ReadCardSerial()) {  //Select one of the cards.
      //Serial.println("select card");
      Blynk.run();
      return;
    }
  }


  //Read "UID".
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    uidDecTemp = mfrc522.uid.uidByte[i];
    uidDec = uidDec * 256 + uidDecTemp;
  }

  if (beginCard == 1 || LockSwitch > 0)EEPROMwriteUIDcard();  //uidDec == adminID

  if (LockSwitch == 0) {
    //CardUIDeEPROMread.
    for (ARRAYindexUIDcard = 0; ARRAYindexUIDcard <= 9; ARRAYindexUIDcard++) {
      if (CardUIDeEPROMread[ARRAYindexUIDcard] > 0) {
        if (CardUIDeEPROMread[ARRAYindexUIDcard] == uidDec) {
          lcd.print(0, 0, "CARD ACCESS OPEN");
          lcd.print(3, 1, uidDec);
          digitalWrite(SLN_PIN, HIGH); //unlock
          digitalWrite(PiezoPin, HIGH), delay(200), digitalWrite(PiezoPin, LOW);
          delay(2000);
          break;
        }
      }
    }

    if (ARRAYindexUIDcard == 10) {
      lcd.print(0, 0, " Card not Found ");
      lcd.print(0, 1, "                ");
      lcd.print(0, 1, "ID : ");
      lcd.print(5, 1, uidDec);
      for (int i = 0; i <= 2; i++)delay(100), digitalWrite(PiezoPin, HIGH), delay(100), digitalWrite(PiezoPin, LOW);
      digitalWrite(SLN_PIN, LOW);  //lock();
      delay(2000);
    }

    ARRAYindexUIDcard = 0;
    DisplayWAiT_CARD();
  }

  Blynk.run();
}

BLYNK_WRITE(V1) {
  int a = param.asInt();
  if (a == 1) beginCard = 1; else beginCard = 0;
}

BLYNK_WRITE(V2) {
  int a = param.asInt();
  if (a == 1) {
    skipCard = 1;
    if (EEPROMstartAddr / 5 < 10) EEPROMwriteUIDcard();
  } else {
    skipCard = 0;
  }
}

BLYNK_WRITE(V3) {
  int a = param.asInt();
  if (a == 1) {
    digitalWrite(SLN_PIN, HIGH); //unlock
    lcd.print(0, 0, " APP UNLOCK OK ");
    lcd.print(0, 1, "   DOOR OPEN   ");
    digitalWrite(PiezoPin, HIGH), delay(200), digitalWrite(PiezoPin, LOW);
    delay(2000);
    DisplayWAiT_CARD();
  } 
}

void EEPROMwriteUIDcard() {

  if (LockSwitch == 0) {
    lcd.print(0, 0, " START REC CARD ");
    lcd.print(0, 1, "PLEASE TAG CARDS");
    delay(500);
    //Serial.println("start card");
  }

  if (LockSwitch > 0) {
    if (skipCard == 1) {  //uidDec == adminID
      lcd.print(0, 0, "   SKIP RECORD   ");
      lcd.print(0, 1, "                ");
      lcd.print(0, 1, "   label : ");
      lcd.print(11, 1, EEPROMstartAddr / 5);
      EEPROMstartAddr += 5;
      skipCard = 0;
    } else {
      //Serial.println("writeCard");
      EEPROM.write(EEPROMstartAddr, uidDec & 0xFF);
      EEPROM.write(EEPROMstartAddr + 1, (uidDec & 0xFF00) >> 8);
      EEPROM.write(EEPROMstartAddr + 2, (uidDec & 0xFF0000) >> 16);
      EEPROM.write(EEPROMstartAddr + 3, (uidDec & 0xFF000000) >> 24);
      EEPROM.commit();
      delay(10);
      lcd.print(0, 1, "                ");
      lcd.print(0, 0, "RECORD OK! IN   ");
      lcd.print(0, 1, "MEMORY : ");
      lcd.print(9, 1, EEPROMstartAddr / 5);
      EEPROMstartAddr += 5;
      delay(500);
    }
  }

  LockSwitch++;

  if (EEPROMstartAddr / 5 == 10) {
    lcd.clear();
    lcd.print(0, 0, "RECORD FINISH");
    delay(2000);
    EEPROMstartAddr = 0;
    uidDec = 0;
    ARRAYindexUIDcard = 0;
    EEPROMreadUIDcard();
  }
}

void EEPROMreadUIDcard() {
  for (int i = 0; i <= 9; i++) {
    byte val = EEPROM.read(EEPROMstartAddr + 3);
    CardUIDeEPROMread[ARRAYindexUIDcard] = (CardUIDeEPROMread[ARRAYindexUIDcard] << 8) | val;
    val = EEPROM.read(EEPROMstartAddr + 2);
    CardUIDeEPROMread[ARRAYindexUIDcard] = (CardUIDeEPROMread[ARRAYindexUIDcard] << 8) | val;
    val = EEPROM.read(EEPROMstartAddr + 1);
    CardUIDeEPROMread[ARRAYindexUIDcard] = (CardUIDeEPROMread[ARRAYindexUIDcard] << 8) | val;
    val = EEPROM.read(EEPROMstartAddr);
    CardUIDeEPROMread[ARRAYindexUIDcard] = (CardUIDeEPROMread[ARRAYindexUIDcard] << 8) | val;

    ARRAYindexUIDcard++;
    EEPROMstartAddr += 5;
  }

  ARRAYindexUIDcard = 0;
  EEPROMstartAddr = 0;
  uidDec = 0;
  LockSwitch = 0;
  DisplayWAiT_CARD();
}

void DisplayWAiT_CARD() {
  lcd.print(0, 0, "   ATTACH THE   ");
  lcd.print(0, 1, "      CARD      ");
  //Serial.println("attach card");
}

Hey Dave, not sure if you simply came across this and started playing with it as a Lockdown project because you were bored, or if it’s of interest as a genuine project?

Storing data in EEPROM is rather old school, and using SPIFFS instead is better because you have more tools/commands available and because it moves the data around to prevent wear of the memory locations (which have a limited read/write life).
Even SPIFFS may start to become old school soon, as the ESP core has a new and improved file system built-in.

The RFID access projects from @Gyromike are quiet a bit more mature. He’s been through a variety of storage options, including an external I2C memory module, but is using SPIFFS…

If you’re looking for a proper project to implement then I think I’d use that as a starting point.

Pete.

Hi Pete, I’ve been thinking about RFID locks for a while, but lock down is a good time to dig deeper. I did see the project you liked and recognized the superiority, I did kinda even have it in mind to figure out this one and maybe move onto Gyromikes project, however I’m a bit daunted by the complexity of it at this point.

First I need to figure out which and how many of his 7 files gets loaded onto which device… :scream:

If you follow the link to his GitHub page you’ll see that there are now 9 files.
If you download the .zip file and unzip it to your Arduino projects file, the rename the folder as “nfc_door_lock_SPIFFS” then open the file called nfc_door_lock_SPIFFS.ino it should open the project with all the files in their correct tabs, readfy for compiling and uploading.

Pete.

Just looking through Gyromike’s code it looks like he is setup for PN532 reader. I only have the RC522 at this point. I’ll have to order the PN532, I want a i2c reader anyways. We’ll have to see if China is still shipping…

Although I like the idea of the PN532, it would be nice if they did one in a weatherproof enclosure to save you having to try to make a weatherproof and tamper proof setup yourself.

Pete.

That why I’m looking at a 3D printer :stuck_out_tongue_winking_eye:

1 Like

I purchased some urethane resin, It is quite cheep and I used a plastic container as a mold. Poured the urethane resin in on top of the device and made it quite water resistant.

I am also available for help at times. Could look at additional sensors if you have one in mind.

I wonder how many calls would need to be changed and what functionality would be lost with RC522 and 522 libraries.

I would need to look at the library calls but it should not change the features. It has i2c interface and I am sure they allow for reading the card ID and that is all that I need.

I dont have the hardware to test it with so you will need to do some work. I am happy to answer questions and to point you it the right direction.

So I cobbled something together (AGAIN) :slight_smile: Uses Blynk and littleFS. I think you could store quite a few cards with a few mods. Right now it is setup for 10 cards.

Checks for a card every 2s.
-If card present checks if it is not stored, if stored open lock, if not stored print message.
-If V1 is pressed it prompts to place card by reader and then Press V2 it then reads the card and compares it to stored cards if it is not in memory and there is still room in memory it adds it.

Edit: the previous code was pretty buggy hope this one is better

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SPI.h>
#include <MFRC522.h>
#include <ArduinoOTA.h>
//littleFS
#include <ArduinoJson.h>
#include "FS.h"
#include <LittleFS.h>

#define SS_PIN D4
#define RST_PIN D3

MFRC522 mfrc522(SS_PIN, RST_PIN);

unsigned long uidDec, uidDecTemp;

char auth[] = "";
char ssid[] = "";
char pass[] = "";

int taptoAdd;
bool addCard = 0;
bool readCard = 1;
bool saveCard;
byte cardIndex = 0;
int unlockState;

int totalNumCards = 2;               ////////////////////////////////////if greater than 99 may not display properly
unsigned long cardUIDlittleFS[2];    ////////////////////////////////////the array # in [?] must be the same as above
int cardAccessControl[2];

WidgetLCD lcd(V0);
BlynkTimer timer;

IPAddress local_IP(192, 168, 0, 47);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8);   //optional
IPAddress secondaryDNS(8, 8, 4, 4); //optional

bool loadData() {
  File dataFile = LittleFS.open("/data.json", "r");                     //populates a "dataFile" from data.json
  if (!dataFile) {
    Serial.println("Failed to open data file");
    return false;
  }

  size_t size = dataFile.size();
  if (size > 1024) {
    Serial.println("Data file size is too large");
    return false;
  }

  // Allocate a buffer to store contents of the file.
  std::unique_ptr<char[]> buf(new char[size]);

  // We don't use String here because ArduinoJson library requires the input
  // buffer to be mutable. If you don't use ArduinoJson, you may as well
  // use configFile.readString instead.
  dataFile.readBytes(buf.get(), size);

  StaticJsonDocument<300> doc;
  auto error = deserializeJson(doc, buf.get());
  if (error) {
    Serial.println("Failed to parse config file");
    return false;
  }

    for(int i=0; i<totalNumCards; i++)                                  //Loads the JSON back into an array on the Arduino
    {
      cardUIDlittleFS[i] = doc["CardUID"][i];
      Serial.println(cardUIDlittleFS[i]);
    }
    Serial.println(" ");

  return true;
}

bool saveData() {                                                       //Saves the array of card Numbers to littleFS
  StaticJsonDocument<300> doc;

  JsonArray CardUID = doc.createNestedArray("CardUID");                 //initializes a JSON array
  for(int i=0; i<totalNumCards; i++)
  {
    CardUID.add(cardUIDlittleFS[i]);                                    //adds each index of the Array to the JSON array
    Serial.println(cardUIDlittleFS[i]);
  }

  Serial.println("Saved \n");
  
  File dataFile = LittleFS.open("/data.json", "w");
  if (!dataFile) {
    Serial.println("Failed to open config file for writing");
    return false;
  }

  serializeJson(doc, dataFile);                                         //Serializes to dataFile
  return true;
}

void readRFID()
{  
  if(readCard == 1)                                                     //Bool to check if reading needs to be paused
  {
    lcd.print(0, 0, " Ready to read  ");
    lcd.print(0, 1, "    Card!       ");
      
    if ( ! mfrc522.PICC_IsNewCardPresent()) {                           //Look for new cards.
      Blynk.run();
      return;
    }
    if ( ! mfrc522.PICC_ReadCardSerial()) {                             //Confirms new card.
      Blynk.run();
      return;
    }
  
    for (byte i = 0; i < mfrc522.uid.size; i++)                         //Reads card and stores UID as int
    {
      uidDecTemp = mfrc522.uid.uidByte[i];
      uidDec = uidDec * 256 + uidDecTemp;
    }

    lcd.print(0, 0, "    Card UID    ");                                //Prints UID
    lcd.print(0, 1, "         ");
    lcd.print(6, 1, uidDec);
                              
    if (saveCard == 0)                                                  //If not save function test if card is registered
    {
      readCard = 0;                                                     //Stop repeated reads for now
        timer.setTimeout(3000L,[]()                                     //Pause for 3s to show UID in display
        {
          for (cardIndex = 0; cardIndex < totalNumCards+1; cardIndex++) //loops through saved cards to see if it is existing, if it is, it aborts
            {      
              if(uidDec == cardUIDlittleFS[cardIndex])                  //Checks till it finds a saved card that matches UID
              {
                unlockState = 1;                                        //Creates a state to use in a lock function
                break;                                                  //Breaks loop if it finds a match
              }
              else                                                      //If it doesn't find a match
              {
                unlockState = 0;                                        //Creates a state to use in a lock function
              }
            }
            uidDec = 0;                                                 // 0s uidDec so the card doesn't get used again in another part of the program
            if(unlockState == 1)
            {
              lcd.clear();
              lcd.print(0, 0, "   Unlocked by  ");                      //Prints UID
              lcd.print(0, 1, "         ");
              lcd.print(6, 1, cardIndex+1);                             //Gives card index of valid card
              ////////////////////unLockDoor();///////////////////////////Calls function to unlock door
            }
        
            if(unlockState == 0)
            {
              lcd.clear();
              lcd.print(0, 0, "    Card not    ");                      //Prints card not stored
              lcd.print(0, 1, "     Stored!!   "); 
            }
            timer.setTimeout(3000L,[]()                                 //Waits to display previous message for 3s
            {
              readCard = 1;                                             //Restarts reading loop
              readRFID();                                               //Fires a read as soon as delay is over instead of waiting till read loop timer
            });
          });
    }
  }
}

void littleFSaddCard()
{
  uidDec = 0;                                                           //avoid using a previously read card
  readRFID();                                                           //get a new read for the following save function
  
  if(saveCard == 1)                                                     //check to stop from looping
  {
    saveCard = 0;                                                       //turns off loop so only reads 1 time
    readCard = 0;                                                       //sets a flag to stop automatic reading till save is finished
    
    if(uidDec == 0)                                                     //Checks if there is actually a card, if not aborts.
      {
        lcd.print(0, 0, "  Error card    ");
        lcd.print(0, 1, "  didn't read   ");
        timer.setTimeout(2500L,[]()
              {
                readCard = 1;                                           //Restarts reading loop
                readRFID();                                             //Fires a read as soon as delay is over instead of waiting till read loop timer
              });
      }
      else
      {
        for (cardIndex = 0; cardIndex < totalNumCards+1; cardIndex++)   //Only gets here if new card
        {
          if(uidDec == cardUIDlittleFS[cardIndex])            
          {
            uidDec = 0;
            lcd.clear();
            lcd.print(0, 0, " Card already in");                        //Displays card in memory
            lcd.print(0, 1, "MEMORY : ");
            lcd.print(9, 1, (cardIndex+1));                             //Displays which index card is in
            lcd.print(11,1, "     ");
            timer.setTimeout(2500L,[]()
              {
                readCard = 1;                                           //Allows card read loop to restart
                readRFID();                                             //Fires a read loop instead of waiting till regular timer
              });
            return;     
          }

          else if(cardIndex < totalNumCards && cardUIDlittleFS[cardIndex] < 1)//find an empty CardUID
          {    
            lcd.clear();
            cardUIDlittleFS[cardIndex] = uidDec;                        //Enters the new UID into to correct Array
            uidDec = 0;
            lcd.print(0, 0, "RECORD OK! IN   ");
            lcd.print(0, 1, "MEMORY : ");
            lcd.print(9, 1, cardIndex+1);                               //Displays the index of the array the card is stored in plus 1
            Serial.println(" ");
            Serial.println(cardIndex);
            Serial.println(" ");
            lcd.print(11,1, "     ");
            saveData();                                                 //Saves the card to littleFS !!!!!!!!!!  very impportant !!!!!!!! 
            timer.setTimeout(3000L,[]()
              {
                lcd.print(0, 0, "  Card Number   ");
                lcd.print(0, 1, "         ");
                lcd.print(6, 1, uidDec);
                Blynk.virtualWrite(V7,1);                               //Populate a new list of cards in table V8
                delay(250);
                Blynk.syncVirtual(V7);                                  //Populate a new list of cards in table V8
                
                timer.setTimeout(1500L,[]()
                  {
                    readCard = 1;                                       //turns scheduled card reading back on
                    readRFID();                                         //Triggers a read card function
                  });
              });
            return;
          }
          else if(cardIndex>=totalNumCards)                              //Throws error message if the array is full
          {
            lcd.print(0,0, " Max Number of  ");
            lcd.print(0,1, " cards reached  ");
            timer.setTimeout(3000L,[]()
                  {
                    readCard = 1;                                       //restarts card reading
                    readRFID();                                         //Triggers a read card function
                  }); 
            return;    
          }
        }
      }
  }
}

BLYNK_CONNECTED()
{
  lcd.clear(); 
  Blynk.virtualWrite(V7,1);                                             //updates the chart of stored cards
  delay(500);
  Blynk.syncVirtual(V7);
}

void setup()
{
  Serial.begin(74880);
  timer.setInterval(2000, readRFID);                                    //Sets RFID reads for every 2s unless flag stops it
  SPI.begin();                                                          //Start SPI communication for RFID reader
  mfrc522.PCD_Init();                                                   //initializes and instance for the reader
  
  if (!LittleFS.begin()) {
        Serial.println("Failed to mount file system");                  //Mounts littleFS system
        return;
      }
  
  if (!loadData())                                                      //Load data from littleFS 
      {
        Serial.println("Failed to load Data");
      } 
      else 
      {
        Serial.println("Data loaded");
      }
      
  WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);     //initializes wifi credentials
  WiFi.begin(ssid,pass);                                                //connects wifi
  Blynk.config(auth);                                                   //initializes Blynk AUTH code
  Blynk.connect();                                                      //Connects to Blynk
  ArduinoOTA.setHostname("RFID Lock");                                  //OTA device name
  ArduinoOTA.begin();                                                   //Starts OTA (has to be after wifi connection)
}

void loop()
{
  Blynk.run();                                                          //Runs Blynk every loop!!!!
  timer.run();                                                          //Runs timer every loop
  ArduinoOTA.handle();                                                  //Keeps OTA working
}

BLYNK_WRITE(V1)     //Tap to start saving card//                        //V1 as Switch to Add card
{ 
  taptoAdd = param.asInt();                                             //Saves a global variable to be used in V2
                 
  if (taptoAdd == 1) 
  {
    readCard = 0;                                                       //Pauses reading before entering save loop
    lcd.print(0,0, "  Hold card on  ");
    lcd.print(0,1,  "reader Tap SAVE ");
  }
}

BLYNK_WRITE(V2)     //Tap to finish save//                              //V2 as Switch to save a new card
{
  if (taptoAdd == 1)                                                    //Checks V1 before entering save loop
  {
    if (param.asInt())
    {
      readCard = 1;                                                     //Allow 1 read to save new card
      saveCard = 1;                                                     //The only place that sets the condition so it is able to enter the save loop
      Blynk.virtualWrite(V2, 0);                                        //Turns switch buttons off so you know the server has seen your message
      Blynk.virtualWrite(V1, 0);                                        //Turns switch buttons off so you know the server has seen your message
      littleFSaddCard();                                                //Calls card save loop
    }
  }
  else
  {
    Blynk.virtualWrite(V2, 0);                                          //If V1 isn't true resets V2
  }
}

BLYNK_WRITE(V5)                                                         //Clears all cards from memory for testing but doesn't save to littleFS
{
  if (param.asInt())
  {
    for(cardIndex=0; cardIndex<totalNumCards; cardIndex++)
    {
      cardUIDlittleFS[cardIndex] = 0;
      Serial.println(cardUIDlittleFS[cardIndex]);
    }
  //saveData();                                                         //uncomment to save cleared table to littleFS
  Blynk.virtualWrite(V7,1);                                             //refeshes table
  delay(500);
  Blynk.syncVirtual(V7);
  }
}

BLYNK_WRITE(V6)                     /////////////////////////enter fake data//////////
{
  if (param.asInt())
  {
    cardUIDlittleFS[0] = 25445;
    cardUIDlittleFS[1] = 41524;
    saveData();
    Blynk.virtualWrite(V7,1);
    delay(500);
    Blynk.syncVirtual(V7);
  }
}

BLYNK_WRITE(V10)                     /////////////////////////enter fake data//////////
{
  if (param.asInt())
  {
    cardUIDlittleFS[0] = 0;
    cardUIDlittleFS[1] = 41524;
    saveData();
    Blynk.virtualWrite(V7,1);
    delay(500);
    Blynk.syncVirtual(V7);
  }
}
BLYNK_WRITE(V11)                     /////////////////////////enter fake data//////////
{
  if (param.asInt())
  {
    cardUIDlittleFS[0] = 25445;
    cardUIDlittleFS[1] = 0;
    saveData();
    Blynk.virtualWrite(V7,1);
    delay(500);
    Blynk.syncVirtual(V7);
  }
}
BLYNK_WRITE(V7)                     /////////////////////////add table at V8//////////
{
  if(param.asInt())
  Blynk.virtualWrite(V8, "clr");
  {
    for(cardIndex=0; cardIndex<totalNumCards; cardIndex++)
    {
      Blynk.virtualWrite(V8, "add", cardIndex, cardUIDlittleFS[cardIndex], cardIndex+1);
    }
  Blynk.virtualWrite(V7,0);
  delay(500);
  Blynk.syncVirtual(V7);
  }
}

Hi Dave,
You might want to think about having an alias/friendly name stored against each card number too.

I take this a step further and have the ability to activate/deactivate RFID tags without actually removing them from the database.
This can be handy when you want to give a tag to a neighbour for example, so they can feed the dog & water the plants etc while your away, but you don’t want to give them unfettered access at other times.

We have a community where every house has a unique RFID tag to allow them to access our community pool. I also have another tag that doesn’t give access to the pool but does open our gate, which the keyholder has.
I can easily enable/disable the stored tag numbers for my various neighbours if I wish. I also use a table in Blynk where I print the friendly name for the tag, and the entry time when it was used. I guess if I wanted to I could set to/from dates when specific tags were activated, or times of day when they were active, but that’s a piece of functionality I don’t need.

I also have a Blynk notification set-up so that whenever a tag that belonging to a neighbour or the keyholder is used I get a alert, using the alias/friendly name that’s assigned to the tag.

Just a bit of food for though before you finalise your code/app :slightly_smiling_face:

Pete.

1 Like

Some questions on your suggestions @PeteKnight
-Do you store your cards in an actual data base or just two separate arrays on for the number and one for the name?
-I had thought of adding a 0 or 1 to the end or the beginning of the card number and use that bit as a true or false. What do you use to identify the card as active or not?

Hmmm, good question!

I had a look at my code and I’m storing them as a SPIFFS file, with “@” characters to separate the records and “|” characters to separate the fields within each record

So, a single record will look like this:

0|123456|Keyholder|1

meaning…

0 - Record ID
123456 - The RFID tag number
Keyholder - Friendly name for the RFID tag
1 - Active = true

Here’s some code snippets that I use…

void slice_file_into_records()
{
  char str[1000];
  int record_counter=0;

  strcpy(str, mystring.c_str()); 
  char * data_record;

    
  data_record = strtok (str,"@");
  while (data_record != NULL)
  {
    DBRecord[record_counter] = data_record;
    data_record = strtok (NULL, "@");
    record_counter++;
  }

}
void slice_records_into_fields()
{
  char * data_field;
  for (int loop = 0; loop <= 9; loop++)
  {
    int field_counter = 0;
    char aaa[50];      
    strcpy(aaa, DBRecord[loop].c_str());
    data_field = strtok (aaa,"|");
    while (data_field != NULL)
    {   
      if (field_counter==0)
      {
        record_ID[loop] = atoi(data_field);
      }
      if (field_counter==1)
      {
        tag_number[loop] = atoi(data_field);
      }      
      if (field_counter==2)
      {
        tag_name[loop] = data_field;
      }       
      if (field_counter==3)
      {
        tag_active[loop] = atoi(data_field);
      } 
            
      Serial.println (data_field);
      data_field = strtok (NULL, "|");
      field_counter++;
    } 
    Serial.println();   
  }
}

I’m sure that there are better/neater solutions, but I knocked this up and it worked, so never revisited it since :wink:

Pete.

As Pete mentioned I did a very extensive project for NFC door locks

@Gyromike and @PeteKnight hats of to both your coding skills I’m not in that league and may never be. I may dig through Mikes code some day but I wanted to post something a little less intimidating as a lot of people that come here probably aren’t at that level yet and can’t sort it all out. If they were the probably would just write their own code :grinning: so hopefully someone can use this for aspiring board.