The library has an option to turn the RFID antenna on and off. Simply shutting it off and turning back on to check the card periodically seems a 100% stable solution.
Obviously you should also check the card hasn't been swapped by checking the ID hasn't changed but here is a a minimal sketch to do this. As checking for a card stops it appearing as new it's easy to get the logic messed up but this is a tested and working example.
Note to self: start putting stuff on GutHub.
#include <SPI.h>#include <MFRC522.h>const uint8_t SS_PIN = D8; //My example code is for a WeMos D1 mini, change these to match your setupconst uint8_t RST_PIN = D0; //My example code is for a WeMos D1 mini, change these to match your setupMFRC522 rfid(SS_PIN, RST_PIN);bool cardPresentWhenLastChecked = false;bool antennaEnabled = true;uint32_t cardCheckTimer = 0;void setup(){Serial.begin(115200);SPI.begin();rfid.PCD_Init();Serial.println(F("Checking for RFID card removal"));}void loop(){if(millis() > cardCheckTimer){//Start a check of the cardif(antennaEnabled == false){//Turn the antenna back onrfid.PCD_AntennaOn();antennaEnabled = true;//It takes time to wake up the RFID card so the sketch needs to wait before checking for itcardCheckTimer = millis() + 20ul;}else if(antennaEnabled == true){if(millis() > cardCheckTimer){//Check for a card after a delay for it to power upif(rfid.PICC_IsNewCardPresent() == true){if(cardPresentWhenLastChecked == false){//Card was absent but has been presentedSerial.println(F("Card presented"));cardPresentWhenLastChecked = true;}}else if(rfid.PICC_IsNewCardPresent() == false && cardPresentWhenLastChecked == true){//The card was present but has been removedSerial.println("Card removed");cardPresentWhenLastChecked = false;}//Switch off the antenna, otherwise the card will not show as 'new' when checked againrfid.PCD_AntennaOff();antennaEnabled = false;//Wait before checking the card againcardCheckTimer = millis() + 100ul;}}}}