BLYNK
HOME       📲 GETTING STARTED       📗 DOCS       ❓HELP CENTER       👉 SKETCH BUILDER

Esp8266 NFC multi door lock system

esp8266

#1

This is an ESP 8266 based project that uses NFC reader PN532 to secure and open doors.

Currently I have only 2 cards and one reader so you will see where I have used the compiler to remove the reader from the two additional doors.

The code has three blynk tokens
in the defines only allow one of these items to be defined.

// only uncoment one at a time
//#define MASTER_LOCK true
#define LOCK1_LOCK true
//#define LOCK2_LOCK true

To add the reader back just remove the # if defined and the # endif in the setup function.

I implemented it as a three door system with a maximum of 20 cards per door. It could easily be upgraded to more doors and more cards per door.

I am still working an a few problems. One is the time the door is active and the other is the copy all button.

The project is in 4 files.

main file


   Creative Commons License
   NFC Door lock
   by Michael Dale Burton
   is licensed under a Creative Commons Attribution-NonCommercial
   4.0 International License.

    Impliments a door lock system using NFC reader and the Blynk app
    Blynk is used to store the data on the cloud and provide
    a smart phone interface for adding, removing and assigning cards
    Device selector is used to choose the lock/door

    20 cards are supported
    2 slaved locks are supported
    1 master  is used as the scanner for adding cards it can also be used as a lock

    Nodemcu esp8266 and PN532 hardware is used

    V1 is a timer
    V2 is a reset button
    V3 ia a text input for the user name assigned to a card
    V4 is a value display for the card id
    V5 current card index "vcount"
    V6 is a terminal window for debug information
    V10 is the delete button
    V24 is a value display for the number of valid cards
    V25 - V45 are reserved for data storage

*/

#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
#include <ESP8266WiFi.h>

/*
  #include <DNSServer.h>            //Local DNS Server for redirecting all requests to the configuration portal
  #include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
  #include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager WiFi Configuration Magic

  #include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson
*/

#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include "globals.h"                    // tab for other defines and globals


PN532_I2C pn532i2c(Wire);
PN532 nfc(pn532i2c);

//create terminal widget instance and attach it to the pin
WidgetTerminal terminal(terminaldisplay);

//Create the real time clock instance
WidgetRTC rtc;

//create timer instance
BlynkTimer timer;

//create bridge instance and assign pins
WidgetBridge bridge1(51);
WidgetBridge bridge2(52);
WidgetBridge bridge3(53);



// get the time and the day
void getCurrentTime() {
  currentTime = String(hour() + ":" + minute());
  currentDate = String(day());
}

void lockDoor() {
  digitalWrite(LED_PIN, LOW);             // turn off LED this causes the door to lock
  Blynk.virtualWrite(lockbutton, 0);      // display door locked on the app
  flag = 0;
}

void unlockDoor() {
  if (!flag) {
    flag = 1;
    digitalWrite(LED_PIN, HIGH);              // send power to unlock the door
    timer.setTimeout(5000L, lockDoor);        // lock the door after 5 seconds
  }
  Blynk.virtualWrite(lockbutton, 1);          // update the app
}

/**************************************
   scanNfc
   Get card data from  NFC hardware

   in: none

   out void

**************************************/
void scanNfc() {

  uint8_t uid[maxuidlength] = {0, 0, 0, 0, 0, 0, 0, 0}; // Buffer to store the returned UID
  String  suid;
  uint8_t uidLength = 0;                          // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
  char holder[maxnamelength];

  /* Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
    'uid' will be populated with the UID, and uidLength will indicate
    if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  */
  nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
  if (uidLength) {
    for (int i = 0; i < uidLength; i++) {
      suid += String(uid[i], HEX);
    }
    Blynk.virtualWrite(cardiddisplay, suid);           // display the uid
    cardIndex = findUid(suid);
    if (cardIndex) {
      unlockDoor();
      Blynk.virtualWrite(namedisplay, cardHolder[cardIndex]); //display the card holder name on the app
      terminal.print(cardHolder[cardIndex]);  // send debug data to the terminal
      terminal.print(" ");
      terminal.print(currentTime);
      terminal.print(" ");
      terminal.println(currentDate);
      terminal.println(cardId[cardIndex]);
      terminal.flush();
      Blynk.virtualWrite(indexdisplay, cardIndex);  // display the card index on the app
      return; // card found
    }
    storeCard(0, suid, String(" "), 0);             //clear card
    Blynk.virtualWrite(namedisplay, " ");           // clear name display on the app
    Blynk.virtualWrite(indexdisplay, 0);            // set index display to 0 on the app
  }
}

/**************************************
  connect to wifi
  connect to blynk server
  create timer
  start nfc
  start I2c
  set I2c rate and pins
  start serial and set speed

**************************************/
void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(RTS_PIN, OUTPUT);
  pinMode(DTR_PIN, OUTPUT);
  uint32_t versiondata = 0; // NFC hardware version

  Wire.setClock(wirespeed);                     // set the Ic2 buss speed
  Serial.begin(serialspeed);                    // open the serial port
  Wire.pins(SDA_PIN, SLC_PIN);                  // SDA, SLC pins
  Wire.begin();                                 // start the Ic2 buss
  nfc.begin();                                  // init the NFC Hardware

  Serial.print(currentTime);
  Serial.println("looking for NFC");

  #if defined MASTER_LOCK
  //search for the NFC hardware
  //this will cause a halt if no hardware found.
  do
  {
    versiondata = nfc.getFirmwareVersion();
    yield();
  } while (! versiondata);
  
  Serial.print(currentTime);
  Serial.println("NFC started");

  nfc.setPassiveActivationRetries(nfcretries);  // Set the max number of retry attempts to read from a card
  nfc.SAMConfig();                              // configure board to read RFID tags

  timer.setInterval(500l, scanNfc);             // scan the NFC every .5 seconds
  #endif
  
  Blynk.begin(blynk_token, ssid, pass);         // start Blynk
  Blynk.syncVirtual(vcount, datapins);          //restore count and card data

}

/**************************************
  main loop
**************************************/
void loop()
{
  Blynk.run();
  timer.run();
}

The Blynk Calls are in file 2.

/*
   NFC Door lock
   Auther Michael Burton

   Creative Commons License
   NFC Door lock
   by Michael Dale Burton
   is licensed under a Creative Commons Attribution-NonCommercial
   4.0 International License.

*/
BLYNK_CONNECTED() {
  // Synchronize time on connection
  rtc.begin();
  bridge1.setAuthToken(reader_token); // Token of reader / lock 0
  bridge2.setAuthToken(lock1_token); // Token of lock 1
  bridge3.setAuthToken(lock2_token); // Token of lock 2
}

/* restore card count

*/
BLYNK_WRITE(vcount) {
  rowIndex =  param.asInt();    //restore the rowIndex

}

// write the rowIndex to the server
BLYNK_READ(vcount)
{
  Blynk.virtualWrite(vcount, rowIndex);
}

// called when the name nameDisplay has had input
BLYNK_WRITE(namedisplay)
{
  cardHolder[0] = param.asStr();   //get the Text Input Widget - String
  if (!findUid(cardId[0]))         // if now card has this id then see if we can add a card
  {
    if (rowIndex < maxcards)      // if the maximum number of cards has not been stored then add a card
    {
      storeCard(++rowIndex, cardId[0], cardHolder[0], accessFlags[0]);                //copy temp data into card memory                                    
    }
  }
}


BLYNK_READ(namedisplay)
{
  Blynk.virtualWrite(namedisplay, cardHolder[0]);   //update the name display on the app
}


BLYNK_WRITE(cardiddisplay)
{
  cardId[0] = param.asStr();  // Text Input Widget - Strings
}


/*
   cycle through the cards

*/
BLYNK_WRITE(indexdisplay) {
  int ci = param.asInt();

  if (ci <= rowIndex) {
    cardIndex = ci;
    getCard(cardIndex);
    Blynk.virtualWrite(namedisplay, cardHolder[0]);
    Blynk.virtualWrite(cardiddisplay, cardId[0]);
  } else {
    cardIndex = rowIndex;
  }
  Blynk.virtualWrite(indexdisplay, cardIndex);
}

/*
    his gets called for any VPin that does not have a defined handler
    this is how data gets stored on the server
*/
BLYNK_WRITE_DEFAULT()
{
  int pin = request.pin;      // get the pin number

  if ((pin >=  DATASTORE) & (pin <= (DATASTORE + maxcards))) {        // if it is a data pin then  store the data
    int i = param[0].asInt();
    cardHolder[i] = param[1].asStr();
    cardId[i] = param[2].asStr();
    accessFlags[i] = param[3].asInt();
  }
}


/*
   Need to be able to copy only to the selected lock

*/
BLYNK_WRITE(copyallbutton)
{
  bridge2.virtualWrite(bridgedata, cardHolder[0], cardId[0], accessFlags[0]);      //copy current card to lock 1
  bridge3.virtualWrite(bridgedata, cardHolder[0], cardId[0], accessFlags[0]);      //copy current card to lock 2

}

BLYNK_WRITE(copybutton)
{
  talktome = 1;
  bridge1.virtualWrite(copybutton, 1);      //copy current card to lock 1
}

/**************************************
  remove a card from valid card list
  moves the last card into the place of the removed card
  decraments the card count
**************************************/
BLYNK_WRITE(deletebutton)  //Remove
{
  if (param.asInt()) {                                                //only do this on the high state of the button press
    if (rowIndex > 1) {                                   // if there is more than one card
      if (cardIndex != rowIndex) {                        // if the current card is not the last card
        getCard(rowIndex);                                // get the last card
        storeCard(cardIndex, cardId[0], cardHolder[0], accessFlags[0]);   //move the data for the last card to the deleted cards position
      } else {
        getCard(--cardIndex);                           //get the previous card and decrament the card index
      }
      --rowIndex;           // decrament the card count

    } else {                                            // remove the last card
      rowIndex = 0;                                     // set the indexes to 0 and clear the strings
      cardIndex = 0;
      cardHolder[0] = " ";
      cardId[0] = " ";
    }
    /*
        update the displayed card data and the number of cards
    */

    Blynk.virtualWrite(vcount, rowIndex);           // store the card count on server
    Blynk.virtualWrite(indexdisplay, cardIndex);    // display the card index
  }
  Blynk.virtualWrite(namedisplay, cardHolder[0]);
  Blynk.virtualWrite(cardiddisplay, cardId[0]);
}



BLYNK_WRITE(lockbutton) {                       //unlock door button pressed
  if (param.asInt()) {
    unlockDoor();
  }
}

BLYNK_WRITE(bridgedata) // copy card to lock hardware
{
  if (talktome) {
    talktome = 0;
    cardHolder[0] = param[0].asStr();
    cardId[0] = param[1].asStr();
    accessFlags[0] = param[2].asInt();

    if (!findUid(cardId[0]))
    {
      if (rowIndex < maxcards)
      {
        rowIndex++;
        storeCard(rowIndex, cardId[0], cardHolder[0], accessFlags[0]);                                    //put card in memory    
        getCard(cardIndex);
      }
    }
  }
}

BLYNK_WRITE(eventorpin) {
  TimeInputParam t(param);

  if (t.hasStartTime())   // Process start time
  {
    SThour = String(t.getStartHour());
    STmin = String(t.getStartMinute());
  }


  if (t.hasStopTime())    // Process stop time
  {
    SPhour = String(t.getStopHour());
    SPmin = String(t.getStopMinute());
  }

  // Process weekdays (1. Mon, 2. Tue, 3. Wed, ...)
  days[0] =  t.isWeekdaySelected(1);
  days[1] =  t.isWeekdaySelected(2);
  days[2] =  t.isWeekdaySelected(3);
  days[3] =  t.isWeekdaySelected(4);
  days[4] =  t.isWeekdaySelected(5);
  days[5] =  t.isWeekdaySelected(6);
  days[6] =  t.isWeekdaySelected(7);

  terminal.println(SThour + ":" + STmin);
  terminal.println(SPhour + ":" + SPmin);
  for (int i = 0; i++; i < 7) {
//    if (days[i]) {
      terminal.print(String(i) + " ");
//    }
terminal.println(" ");
  }
  terminal.flush();
}


/**************************************
  remove all cards from valid card list
**************************************/
BLYNK_WRITE(resetallpin)  //reset
{
  rowIndex = 0;
  cardIndex = 0;
  Blynk.virtualWrite(namedisplay, " ");
  Blynk.virtualWrite(cardiddisplay, " ");
  Blynk.virtualWrite(vcount, rowIndex);
  Blynk.virtualWrite(indexdisplay, rowIndex);
}

The data is handled in the third file.

/*
   NFC Door lock
   Auther Michael Burton

   Creative Commons License
   NFC Door lock
   by Michael Dale Burton
   is licensed under a Creative Commons Attribution-NonCommercial
   4.0 International License.

*/
/**************************************
  compairUid return bool

  in: card ids

  out: true if they are the same else false
**************************************/
bool compairUid(uint8_t uid1[], uint8_t uid2[], uint8_t j) {
  for (int i = 0; i < j; i++) {
    if (uid1[i] != uid2[i]) {
      return false;
    }
  }
  return true;
}

/*****************************************************
   findUid
   takes uid and length
   return index of uid in array or 0 if not found

*/
int findUid(String suid) {
  for (int i = 1; i <= rowIndex; i++) {
    if (!(suid.compareTo(String(&cardId[i][0])))) {
      return i; // index of card found
    }
  }
  return 0;
}

/**************************************
  storeCard
  in: row index, card Id, id length, card holder name

  places the uid and the name in the hardware memory at index location ri

  out: none
**************************************/
void storeCard(int ri, String suid2, String holder, int af) {
  cardId[ri] = suid2; // save uid as a string
  cardHolder[ri] = holder;                        // save name of card holder
  accessFlags[ri] = af;
  Blynk.virtualWrite(vcount, rowIndex);                                                             //save the card count on the server
  Blynk.virtualWrite(DATASTORE + ri, ri, cardHolder[ri], cardId[ri], accessFlags[ri]);     //save card data on server
  Blynk.virtualWrite(indexdisplay, ri); 
}

void getCard(int index) {
  cardId[0] = cardId[index];                      // get cardId
  cardHolder[0] = cardHolder[index];              // get name of card holder
  Blynk.virtualWrite(namedisplay, cardHolder[0]); // display the card holder on the app
  Blynk.virtualWrite(cardiddisplay, cardId[0]);   // display card id on app
}

/***************************************
   read card id access flags and user name from the cloud
   (datastore + index) is the virtual pin for the card data
**************************************/
void readFromCloud(int count) {
  for (int i = 0; i < count; i++) {
    Blynk.syncVirtual(DATASTORE + count);
  }
}

The Last file has the defines and global data.

/*
   NFC Door lock
   Auther Michael Burton

   Creative Commons License
   NFC Door lock
   by Michael Dale Burton
   is licensed under a Creative Commons Attribution-NonCommercial
   4.0 International License.

*/
//#define BLYNK_PRINT Serial  // Comment this line out to disable prints and save space 
//#define BLYNK_DEBUG

// only uncoment one at a time
//#define MASTER_LOCK true
#define LOCK1_LOCK  true
//#define LOCK2_LOCK  true
/*
   hardware defines
*/
#define wirespeed 400000L   // Ic2 buss speed
#define serialspeed 115200  // serial port speed
#define nfcretries 0x0f     // number of passive retries before timeout on nfc hardware 

/*
                                PIN MAP for ESP8266
*/
#define SDA_PIN     2             // I2C SDA pin
#define SLC_PIN     14            // I2C SCL pin

#define RTS_PIN     4             // RTS line for C17A - DB9 pin 7
#define DTR_PIN     5             // DTR line for C17A - DB9 pin 4

#define RELAY_PIN   8             // relay output pin
#define LED_PIN     16            // attached LED



/********************************************************************************************

   BLYNK V PIN MAP

 ********************************************************************************************/
#define clockpin        V1
#define resetallpin     V2
#define namedisplay     V3
#define cardiddisplay   V4
#define indexdisplay    V5
#define terminaldisplay V6
#define copybutton      V11
#define copyallbutton   V7
#define lockbutton      V8
#define bridgedata      V9
#define deletebutton    V10
#define eventorpin      V14
#define vcount          V24
#define DATASTORE       V25
#define datapins        V25, V26, V27, V28, V29, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V40, V41, V42, V43, V44, V45


#define maxcards      20
#define maxnamelength 20
#define maxuidlength  8
#define flagslength   1

const char*  daystrings[7]  =  {"Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"};

/* BLYNK tokens

*/
char reader_token[] = "blynk token one of the locks";
char lock1_token[] = "blynk token one of the locks";
char lock2_token[] = "blynk token one of the locks";


#if defined(MASTER_LOCK)

char blynk_token[] = "blynk token one of the locks";

#elif defined(LOCK1_LOCK)

char blynk_token[] = "blynk token one of the locks";

#else

char blynk_token[] = "blynk token one of the locks";

#endif
/*
    WiFi credentials.
*/
char ssid[] = "wifiname";
char pass[] = "password";

/*
    Global data
*/
String  cardId[maxcards + 1];
String  cardHolder[maxcards + 1];
int     accessFlags[maxcards + 1];
String  SThour;
String  STmin;
String  SPhour;
String  SPmin;
int     days[7];
int     flag = 0;


int     cardIndex = 0;
int     rowIndex = 0;
String  currentTime;
String  currentDate;
int talktome = 0;

#2

Here is a very short video of the project in operation.

video of door lock

You will see that the relay is active for 5 seconds after each time a card is read that is on the system.

if a card is read on the master that is not stored in the system you can add the card to any door.

cards can be moved to any door or removed. the activity is logged in the terminal.


#3

Nice for video and projects. Thank you.


#4

Hi @Gyromike, nice project.
I’ve not studied your code, but from your description I guess that the system won’t work without your Wi-Fi and the Blynk server that you’re using being online?

I have a somewhat simpler system which uses just one RFID tag code (because I want the unique tag that’s used to access your comm7nity swimming pool to also open our gate). My single code is hard-coded into my sketch, but Blynk can be used to release the gate remotely, and a Blynk table is used to store info about when the gate has been released and how.

I get around the need to be online all the time by hard-coding my single RFID code I to my sketch (easy for me with gust one code) and using a non-blocking connection that will carry-on working if there’s no internet connection, and will try to re-connect periodically.

Had I needed to use more codes then I’d probably have explored the idea of storing them in the SPIFFS memory of the NodeMCU, with an option to add/remove via Blynk.

When I put my system together it worked perfectly on the bench, but went haywire when I connected it up to the gate release. My gate uses an AC release, which makes a buzzing noise for the 5 seconds that it’s avtivated. It turns-out that the issue was EMF feedback from the coil on the gate release, which I eventually solved with a capacitor across the sontacts of the relay. From memory, I think it was around 100uf.
If you, or anyone else trying this project, has similar issues with an AC lock release then this tip might save you a bit of head scratching.

Here’s some info on my project, which is very different because it uses Node-Red and MQTT as well as Blynk…

Pete.


#5

Thanks Pete,

The code has local storage that gets refreshed by the cloud on connect. It was working to open the locks offline but I have not checked it recently. I may have broken it in that regard.

Recently I have purchased some chips that have persistent storage that work with little power over i2C buss. I will augment the cloud storage with this in the next version and make sure that it will work offline.

Right now I am testing the locks on my home and hangar. So far so good.

It is a fun hobby for me. I retired from software engineering a few years back and this is a revival for me. I was quite burned out. I am now in it mostly for fun.

The things that drive me crazy are egomaniacs that think they are the sun and the moon. but I am good now at letting them think what they want and going my own way.

I have a lot of ideas for new projects.


#6

Good to hear that you’re doing some hobby stuff for fun now.

Many moons ago I was a professional photographer and when I changed careers it took me a long time to re-discover photography as a hobby. It can take quite a while to get out of the ‘working for the client’ mindset and starting to enjoy doing stuff for yourself instead.

Sounds like you have another hobby too though, which I guess is where your username comes from?

Pete.


#7

I love photography also. One of my passions. I don’t do portraits!

The name comes from my involvement in Aviation. It is a life long love.


#8

good job !
but what did you expect in case the nodemcu crashes?
do you have planned a nodemcu auto reset ? :fearful:


#10

Today i completed adding FRAM storage for the backup data. I used the small FRAM from Adafruit. It works over the I2c buss.

It was a fun addition it is now working.

This week I am going to work on the enclosures. To this point there have been no problems with the locks. The testing has been without event. The locks have been up for two weeks now except when I update them. I have been leaving one online to see how long it will be before it goes offline.

I have tested power cycles and network outages. :slight_smile:


#11

fram%20and%20card%20reader%20on%20adafruit%20board

Here is the reader and the FRAM connected to the adafruit ESP8266 board


#12

Here is the code for the file storage on the FRAM.

I used the Adafruit library but it was quit limited. so I wrote so additional bits to make it easy for myself to reuse.

you will nee to include “Adafruit_FRAM_I2C.h”

it still has some debug lines in my code as you will see.

call startfram(); it will make sure the Ic2 address is valid and print “fram started” when the FRAM is ready. It is non blocking.

I used it like this

timer.setInterval(700l, startfram); // scan for valid FRAM address every .7 seconds

It will continue to check the FRAM until it gets a valid address. then the code will just return without doing anything.




void startfram() {
  if (validfram) {
    return;
  } else {
    validfram = fram.begin(IC2_FRAM_ADDRESS);
    if (!validfram) {
      yield();
    } else {         
      terminal.println("fram started: ");
      terminal.flush();
      getdatafromfram();
    }
  }
}

void readrawdata(uint16_t whatbyte, int howlong, char databuffer[]){
    for (int j = 0; j < howlong; j++){
      databuffer[j] = fram.read8(DATASTART+whatbyte+j);
      yield();
    }
}

void writerawdata(uint16_t whatbyte, int howlong, char databuffer[]){
    for (int j = 0; j < howlong; j++){
       fram.write8(DATASTART+whatbyte+j, databuffer[j]);
      yield();
    }
}

void writestringdata(uint16_t whatbyte, int howlong, String databuffer){
   
    for (int j = 0; j < howlong; j++){
       fram.write8(DATASTART+whatbyte+j,  databuffer.charAt(j));
       yield();
    }
}

String readstringdata(uint16_t whatbyte, int howlong){
  char s[256];
    for (int j = 0; j < howlong; j++){
      s[j] = fram.read8(DATASTART+whatbyte+j);
      yield();
    }
    return String(s);
}

uint16_t read16data(uint16_t whatbyte){
  uint8_t high = fram.read8(DATASTART+whatbyte);
  uint8_t low = fram.read8(DATASTART+whatbyte+1);
  uint16_t out;
  out = high << 8;
  out += low;
  return out;
 }

void write16data(uint16_t whatbyte, uint16_t databuffer){
  uint8_t high = highByte(databuffer);
  uint8_t low = lowByte(databuffer);
  fram.write8(DATASTART+whatbyte, high);
  fram.write8(DATASTART+whatbyte+1, low);
 }
 
void getdatafromfram(){
  rowIndex = read16data(0);                                                   //read the card count from fram 
  uint16_t buffer_offset = recordlength;                                    //start at record 1
    Blynk.virtualWrite(vcount, rowIndex);       // write the rowIndex to the server
    
  for (int i = 1; i <= rowIndex; i++){                                             // read all the card data
//    tempindex = read16data(buffer_offset);                                       // skip the index
    buffer_offset += 2;
    cardHolder[i] = readstringdata(buffer_offset, maxnamelength);
    buffer_offset += maxnamelength;
    cardId[i] = readstringdata(buffer_offset, maxuidlength);
    buffer_offset += maxuidlength;
    accessFlags[i] = read16data(buffer_offset);
    buffer_offset += 2;
    yield();
  }
}

void dumpdatafromfram(){
  String ch;
  String cId;
  int af;
  int ri;
  int tempIndex;
  uint16_t buffer_offset = recordlength;                                    //start at record 1


    tempIndex = read16data(0);                                                   //read the card count from fram address 0
  for (int i = 1; i <= tempIndex; i++){                                             // read all the card data
    ri = read16data(buffer_offset);
    buffer_offset += 2;
    ch = readstringdata(buffer_offset, maxnamelength);
    buffer_offset += maxnamelength;
    cId = readstringdata(buffer_offset, maxuidlength);
    buffer_offset += maxuidlength;
    af = read16data(buffer_offset);
    buffer_offset += 2;
    terminal.println("index: " + String(ri) + " holder:  " + ch + " ID:  " + cId + " flags: " + String(af));
    yield();
  }
  terminal.flush();
}


#13

Alexis,

It restores the data when it reconnects to the server. The data is also stored in FRAM. On startup the data is restored and the lock returns to function even if the cloud does not connect.


#14

32kb for $10, right?

Why not use the free 3MB of SPIFFS that most ESP8266’s have?


#15

you’re right, Costas,
it’s better to use nodemecu RAM SPIFFS.
it’s a scam the 32k for $ 10 !
nodemecu is only 2.50$ with 4 Mb.
:scream:


#16

I can’t be sure of the capacity or voltage requirements… but they do seem a bit expensive…

image


#17

The advantage of FRAM memory is that it has a life of around 10,000,000,000,000 read/write cycles, as opposed to 100,000 for the Winbond memory used by SPIFFS.
Obviously in this scenario, the number of times data needs to be written to SPIFFS is limited, as it only needs to be used to store a few RFID key tag numbers, and these won’t change very often, but it also has the advantage of not being overwritten when flashing your NodeMCU code if you don’t take care about which flash mode you use.

Pete.


#18

For no good reason. I just like playing with hardware and software. It was an enjoyable exercise.

You are right it is a bit expensive for the size of memory. The memory was made for things that need very rapid access to persistent storage and it is new. I am sure the cost will go down as it has for other storage media.

I will explore using the internal memory.


#19

Funny Peter,

Thanks for taking another look.


#20

I purchased them in 2 sizes 8kb and 32kb. Yes this is a bit more than some options for data storage.


#21

For a house it does not change much but for a hotel it would change every day. Still 100,000 cycles would last quite some time.

One big advantage is that it does not get erased on update.