String comparison returns false... using .readStringUntil

Hello,

I have managed to save and retrieve a String of IDs from SD and the problem that I'm facing is with comparing the two Strings. Using .readStringUntil('\n') for retrieving IDs from SD line by line.

  bool codeFound() {
  String codesFoundOnSD;
  Serial.println("Retrieving codes...");
  codesFile = SD.open("codes.txt");

  // if the file is available, read from it.
  if (codesFile){
    while (codesFile.available()) { 
            codesFoundOnSD = codesFile.readStringUntil('\n');
        Serial.println("ID found on SD:" + codesFoundOnSD); 
        if(uidChar.equals(codesFoundOnSD)) {            
        Serial.println("MATCH FOUND!");
            return true; 
        } 
        delay(50);        
    }
  } else {
    // if the file isn't open, show an error:
    errorOpeningFile();
  }
  return false;
}

The serial out of the two variables seems a perfect match yet the comparison is returning false.

And here is the full code if I'm messing something else up...

#include <SD.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_PN532.h>

#define PN532_SCK  (9)
#define PN532_MOSI (7)
#define PN532_SS   (8)
#define PN532_MISO (2)
#define SDPIN (10)

#define LEDRED (A0)
#define LEDGREEN (A1)
#define BUZZER (A2)
#define DOOR (A3)

Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);

File codesFile;

String uidChar = "";

void setup(void) {

  Serial.begin(115200);
  Serial.println("Hello!");

  pinMode(LEDRED, OUTPUT);
  pinMode(LEDGREEN, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  pinMode(DOOR, OUTPUT);

  Serial.print("Initializing SD card...");

  //  For SDCard to work (cc3000)
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);

  if (!SD.begin(4)) {
    Serial.println("Initialization failed!");
    return;
  }
  Serial.println("Initialization done.");

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);

  // configure board to read RFID tags
  nfc.SAMConfig();
  Serial.println("Waiting for a Card ...\n");

}


void loop(void) {

  uint8_t readSuccess;
  uint8_t unregisteredReadSuccess;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  readSuccess = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  if (readSuccess) {
    delay(1000);
    for ( int i = 0; i < 4; i++ ) {
      uidChar +=  uid[i];
    }
    Serial.println("ID:" + uidChar);
    // Card successfully read indication.
    for (int i = 0; i < 4; i = i + 1) {
      digitalWrite(LEDGREEN, HIGH);
      digitalWrite(LEDRED, HIGH);
      digitalWrite(BUZZER, HIGH);
      delay(50);
      digitalWrite(LEDGREEN, LOW);
      digitalWrite(LEDRED, LOW);
      digitalWrite(BUZZER, LOW);
      delay(50);
    }

    delay(250);

    if (uidChar == "5319725153") {
      Serial.println("Mastercard found");
      digitalWrite(LEDGREEN, HIGH);
      digitalWrite(LEDRED, HIGH);
      digitalWrite(BUZZER, HIGH);
      digitalWrite(DOOR, HIGH);
      delay(250);
      digitalWrite(DOOR, LOW);
      Serial.println("Door Unlocked");
      delay(1000);
      Serial.println("Waiting for a new card to be programmed...");
      delay(500);
      uint8_t uidTwo[] = { 0, 0, 0, 0, 0, 0, 0 };
      uint8_t uidLengthTwo;
      unregisteredReadSuccess = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uidTwo, &uidLengthTwo);

      if (unregisteredReadSuccess) {
        digitalWrite(LEDGREEN, LOW);
        digitalWrite(LEDRED, LOW);
        digitalWrite(BUZZER, LOW);
        String uidCharTwo = "";
        for ( int i = 0; i < 4; i++ ) {
          uidCharTwo +=  uidTwo[i];
        }
        Serial.println("ID:" + uidCharTwo);
        if (uidCharTwo == "5319725153") {
          for (int i = 0; i < 6; i = i + 1) {
            digitalWrite(LEDGREEN, HIGH);
            digitalWrite(LEDRED, HIGH);
            digitalWrite(BUZZER, HIGH);
            delay(100);
            digitalWrite(LEDGREEN, LOW);
            digitalWrite(LEDRED, LOW);
            digitalWrite(BUZZER, LOW);
            delay(100);
          }
          delay(500);
          
          SD.remove("codes.txt");          
          
          digitalWrite(LEDGREEN, HIGH);
          digitalWrite(LEDRED, HIGH);
          digitalWrite(BUZZER, HIGH);
          delay(250);
          digitalWrite(LEDGREEN, LOW);
          digitalWrite(LEDRED, LOW);
          digitalWrite(BUZZER, LOW);
          Serial.println("MASTER-RESET Completed!\n");
        } else {
          delay(500);
          digitalWrite(LEDGREEN, HIGH);
          digitalWrite(LEDRED, HIGH);
          digitalWrite(BUZZER, HIGH);
          delay(250);
          digitalWrite(LEDGREEN, LOW);
          digitalWrite(LEDRED, LOW);
          digitalWrite(BUZZER, LOW);
          delay(500);

          codesFile = SD.open("codes.txt", FILE_WRITE);

          if (codesFile) {
            codesFile.println(uidCharTwo);
            codesFile.close();
            // print to the serial port too:
            Serial.println("ID written to SD card:" + uidCharTwo);
          } else {
            // if the file isn't open, show an error:
            errorOpeningFile();
          }

          digitalWrite(LEDGREEN, HIGH);
          digitalWrite(BUZZER, HIGH);
          delay(500);
          digitalWrite(LEDGREEN, LOW);
          digitalWrite(BUZZER, LOW);
          Serial.println("New card registered!\n");
        }
      }
    } else {


      if (codeFound()) {
        digitalWrite(LEDGREEN, HIGH);
        Serial.println("ACCESS GRANTED");
        delay(300);
        digitalWrite(DOOR, HIGH);
        delay(250);
        Serial.println("Door Unlocked!\n");
        digitalWrite(DOOR, LOW);
        delay(450);
        digitalWrite(LEDGREEN, LOW);
      } else {
        Serial.println("ACCESS DENIED\n");
        digitalWrite(LEDRED, HIGH);
        digitalWrite(BUZZER, HIGH);
        delay(1000);
        digitalWrite(LEDRED, LOW);
        digitalWrite(BUZZER, LOW);
      }
      // delay till the next read
      delay(2500);
    }
  }             
   uidChar = "";   
   codesFile.close();
}

  bool codeFound() {
  String codesFoundOnSD;
  Serial.println("Retrieving codes...");
  codesFile = SD.open("codes.txt");

  // if the file is available, read from it.
  if (codesFile){
    while (codesFile.available()) { 
            codesFoundOnSD = codesFile.readStringUntil('\n');
        Serial.println("ID found on SD:" + codesFoundOnSD); 
        if(uidChar.equals(codesFoundOnSD)) {            
        Serial.println("MATCH FOUND!");
            return true; 
        } 
        delay(50);        
    }
  } else {
    // if the file isn't open, show an error:
    errorOpeningFile();
  }
  return false;
}

void errorOpeningFile() {  
  Serial.println("Error opening codes.txt");
for (int i = 0; i < 5; i = i + 1) {
    digitalWrite(LEDGREEN, HIGH);
    digitalWrite(LEDRED, HIGH);
    digitalWrite(BUZZER, HIGH);
    delay(1000);
    digitalWrite(LEDGREEN, LOW);
    digitalWrite(LEDRED, LOW);
    digitalWrite(BUZZER, LOW);
    delay(1000);
  }
}

Your code does not seem to define what uidChar is

uidChar is a String defined before the "setup" function...

I suggest that you make a modification like this

Serial.println("ID found on SD:" + codesFoundOnSD);
Serial.println("uidChar is:" + uidChar);
if(uidChar.equals(codesFoundOnSD)) {

And then your problem might be clearer.

This bit of code looks odd to me:

while (codesFile.available()) {

I've never tried reading a file that way, but then I am old-fashioned. Do you expect to have more than one codesFoundOnSD String in your file on SD ?

while (codesFile.available()) {
            codesFoundOnSD = codesFile.readStringUntil('\n');
        Serial.println("ID found on SD:" + codesFoundOnSD);
        if(uidChar.equals(codesFoundOnSD)) {           
        Serial.println("MATCH FOUND!");
            return true;
        }
        delay(50);       
    }

Where do you think the "ACCESS DENIED" message comes from ?

You need to consider that the readStringUntil( ) function might return a null object reference.

If you think the problem is in the String .equals( ) function, you can clarify where it is actually failing by writing something like this:

while (codesFile.available()) {
            codesFoundOnSD = codesFile.readStringUntil('\n');
        Serial.println("ID found on SD:" + codesFoundOnSD);
        if(uidChar.equals(codesFoundOnSD)) {           
        Serial.println("MATCH FOUND!");
            return true;
        }
        else
        {   
              Serial.println("No match") ;
        }
        delay(50);       
    }

If you see this, or don't see this, that will help to determine where your logic is failing.

You could also try adding more values to the file, and see what happens. Does it fail when it reads the second one, or the last one ?

If there is any possibility of this code being called more than once, it is probably a good idea to close the file before you return true with your match found.

Both the Strings are perfectly equal no spaces etc...

The problem seems to be with the .readStringUntil() function.. I guess it's adding somekinda hidden characters or something to it. As I was using char to String and retrieving the data on SD one by one... and the comparison was fine... but I was having isseues with multiple ID comparison...

Is there is a workaround with the situation.. I just want to compare the multiple IDs stored on SD (line by line) with the one scanned at the moment and return true if any match is found.

Well you seem to have two separate issues.

The first one is, why don't the strings match ?

The second one is, what is going wrong after that ?

One issue with strings, is that you need to know the difference between: Are these two strings the same actual string (OBJECT), and do these two different strings have exactly the same letters in them ?

That's the same difference as asking " if ( string1 == string 2 )" and " if ( string1.equals( string2 ))"

That does not seem to be your issue. Although they look the same, one of them might have a 0 byte or a carriage return or something at the end, which isn't displayed on the screen. Try printing the number of characters in each string.

As for your second issue, how many ID's in the SD file. Add some more. Does it always fail the second time, or the last time ?

Add a check for a null string object.

         codesFoundOnSD = codesFile.readStringUntil('\n');
        if ( null == codesFoundOnSSD ) Serial.println("  read null object ");
        else  Serial.println("ID found on SD:" + codesFoundOnSD);

Is that Serial.println( ) valid C++ ? Looks like java to me.

FIXED!

Had to add codesFoundOnSD.trim();

  bool codeFound() {
  String codesFoundOnSD;
  Serial.println("Retrieving registered codes...");
  codesFile = SD.open("codes.txt");

  // if the file is available, read from it.
  if (codesFile){
    while (codesFile.available()) { 
            codesFoundOnSD = codesFile.readStringUntil('\n');
            codesFoundOnSD.trim();
        Serial.println("ID found on SD: " + codesFoundOnSD);
        if(uidChar == codesFoundOnSD) {            
        Serial.println("MATCH FOUND!");
            return true; 
        }
    }
  } else {
    // if the file isn't opening, show an error:
    errorSDAccess();
  }
  return false;
}

If the character string actually is ended with \r\n instead of just \n, then the \r carriage return byte will be a non printable (aka, you won't see it) trash byte captured on the end of your String. You don't see it, but the comparison code does.

codesFoundOnSD = codesFile.readStringUntil('\n');

Thanks for great help karma