Making a log in form

Hello everyone, Im trying to do a simple log in form which will displayed on serial monitor if possible for now.

My question is it possible to create a database using sd card as I search about simple read and write data on it? Or should I use internet and connect some database from the web server but I only seen an arduino writing temperature on it but not retreiving data from database.

the log in form contains two text boxes that will contain the input username and the password.

Thank you in advance :slight_smile:

Yes. The key here is to keep it simple.

I guess that depends on whether you want to update the database remotely or not. What would happens if the internet connection dies? Do you still need your login to work? Maybe a hybrid solution where you can update the database on a webserver and have your Arduino check it periodically and download any updated database to the SD card.

A database is anything that stores data. If the Arduino example you saw wrote a time and a temperature to a plain text file, then that's a database.

You can start simply with a plain text file on an SD card. Each line in the text file is a plain text username followed by a separator - usually a comma - and then the plain text password. Each time a username and a password pair are entered, you can open your text file and read in username & password pairs until you get a username match. Then check the passwords to see if they match.

Once you get that working, you can think about encrypting the information.

I have implemented databases on SD before. I usually define a structure which represents all the data of a record I want to store/retrieve and usually also a union so that the entire structure is also represented as a simple byte array which is easier to write/read. Back in the day, we used this method too and eventually also added pointers to the preceding/following record. This was known as ISAM and provided for having the records "sorted".

I guess I will stick on creating database on SD card so the product will not required any internet connection to read/write database.

Can I know how do I find certain string and how can I update it if I want to change password for example?

For example

UserId and password has been typed but there's another variable which is the username that will display if the credentials typed is correct.

I'm thinking about saving an array for each user on sd card on this format:

String user_data[2] = {"userId" , "password", "userName"};

Thanks for you response and I apologize for late reply

Thanks, I will research the method ISAM you're referring to. But I will firstly buy sd card module as I didn't have that module fearing that I will bought wrong equipment for this project.

Sorry for late response by the way.

I've not done it on an Arduino, but I can think of 2 methods:

Method 1:

  • Create a new username/password file
  • Copy all the username & password data from the old file to the new file until you reach the entry you want to change.
  • Read in the entry you want to change
  • Apply the change(s)
  • Write out the new entry
  • Copy the remaining username & password date from the old file to the new file.

However, off the top of my head, I don't think the SD library has a function to rename a file - if you were to delete the old file and rename the new file, for example.

Method 2:

This relies on allocating a fixed number of characters/bytes for each username and password. Say you had a maximum of 16 characters for each username and another 16 characters for the password. If all username & password entries were fixed like this, then you have a file of fixed length records.

In theory, you would:

  • Open the username/password file for read/write
  • Read each fixed length record one at a time until you find the one you want to change
  • Change the username or password in the record you've just read in
  • Use the position() function to discover where you are in the file
  • The use the seek() function to go back 1 record : it's the value returned by position() - 1x record size
  • Write out the new username & password record
  • Close the file

That's the theory. You would need to experiment to see if the SD library would support these methods.

I had a play and here's a dirty example of method #2:

/*
  SD card test to see if it's possible to Read - Modify - Write a file
*/
// include the SD library:
#include <SPI.h>
#include <SD.h>
#include <myMicroBusDefs.h>

File myFile;

// change this to match your SD shield or module;
const int chipSelect = MB_S1_SPI_CS;

uint8_t oneRecord[16] = { 'U','s','e','r','N','o','0','1','P','a','s','s','0','0','0','1' };
 
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  Serial.print("\nInitializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  if ( SD.exists("test.dat") ) SD.remove("test.dat");

  createTestFile();
  displayTestFileContents();
  changePassword( 3 , "PassABCD" );
  displayTestFileContents();
}

void loop() {
  // nothing happens after setup
}

void createTestFile() {
  myFile = SD.open("test.dat", FILE_WRITE);

  // if the file opened okay, write some sample data to it:
  if (myFile) {
    Serial.println("\nWriting test records to test.dat...");
    for (uint8_t a='1'; a<':'; a++) {
      oneRecord[7] = a;
      oneRecord[15] = a;
      myFile.write( oneRecord, sizeof(oneRecord) );
    }
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.dat");
  }  
}

void displayTestFileContents() {
  myFile = SD.open("test.dat");
  if (myFile) {
    Serial.println("\nReading test records from test.dat...");
    // read records from the file until there's nothing else in it:
    while (myFile.available()) {
      myFile.read( oneRecord, sizeof(oneRecord) );
      for (uint8_t i=0; i<sizeof(oneRecord); i++) {
        Serial.print( (char)(oneRecord[i]) );
      }
      Serial.println();
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

void changePassword( uint8_t user, const char *pwd ) {
  uint32_t filePos = 0;
  
  myFile = SD.open("test.dat", O_RDWR);

  // if the file opened okay, change the password
  if (myFile) {
    Serial.println("\nChanging password in test.dat...");
    // calculate the location of the record to change
    filePos =  (user - 1) * sizeof(oneRecord);
    // add the offset to the password
    filePos = filePos + 8;
    // go there
    myFile.seek( filePos );
    for (uint8_t x=0;x<8;x++) {
      myFile.write( pwd[x] ); 
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

There's little error checking and hard coding of values etc, but it will give you an idea of how to do it.

EDIT: Output looks like this:

Initializing SD card...initialization done.

Writing test records to test.dat...
done.

Reading test records from test.dat...
UserNo01Pass0001
UserNo02Pass0002
UserNo03Pass0003
UserNo04Pass0004
UserNo05Pass0005
UserNo06Pass0006
UserNo07Pass0007
UserNo08Pass0008
UserNo09Pass0009

Changing password in test.dat...

Reading test records from test.dat...
UserNo01Pass0001
UserNo02Pass0002
UserNo03PassABCD
UserNo04Pass0004
UserNo05Pass0005
UserNo06Pass0006
UserNo07Pass0007
UserNo08Pass0008
UserNo09Pass0009

1 Like

Actually, that won't work. It is true that arrays are numbered beginning with 0 and so an array with three elements is x[0], x[1] and x[2). However, when declaring an array, the number you must give is the NUMBER OF elements, not the number of the LAST element. So, in your line, change the 2 to a 3 or it won't compile.

Next topic, on an Arduino, it is seldom (maybe never?) a good idea to use String. They can (will?) cause memory issues and may ultimately end with a crash.

As I said before, personally, I would define my record as a structure, each element of a given length. Such as:

typedef struct user{
  char Id[10];
  char password[10];
  char name[25];}
user;

After declaring that structure that way, you use it just as a data type. So you declare a single instance of that structure like this: user myUser;

You address those individual elements like this: myUser.Id = "GeorgeW"; or if( myUser.name == "George Washington").

That structure can easily be written to and read from SD with

myFile.write((char *)&myUser,sizeof(myUser));
myFile.read((char *)&myUser,sizeof(myUser));

For now, just accept that it has to be written that way and don't worry about what the (char *)& means. Pointers are a more advanced topic than this thread was meant to handle.

So, back to ISAM. That stands for Indexed Sequential Access Method and that is exactly what we have talked about up to this point except for the "Indexed" part. See if you can get it working as discussed up to this point and we can go into indexing the records later if you need to.

hello, so my sd card module and my sd card (32 gb) just delivered today so i tried to format it to fat32 type and I'm following some tutorials for basic write and read. My problem is the program wont write and read cause sd wont begin. Is there anything wrong with my wiring?

#include <SPI.h>
#include <SD.h>
File myFile;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.print("Initializing SD card...");
if (!SD.begin(10)) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
myFile = SD.open("test.txt", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to test.txt...");
myFile.println("This is a test file :)");
myFile.println("testing 1, 2, 3.");
for (int i = 0; i < 20; i++) {
myFile.println(i);
}
while (myFile.available()) {
Serial.write(myFile.read());
}
// close the file:
myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}
void loop() {
// nothing happens after setup
}

and also the module voltage input is 5v so I put it on 5v, also why do the tutorial had mosi but my module had moso.

The key here is to keep it simple, that's it!

1 Like

Not that I have great amounts of experience, but my SD modules have MOSI and MISO, but no MOSO. Are you sure you're reading it correctly? Also, the pinout on some SD modules is different, as in the same pins, but different order, so be conscious of that. It may be a difference between the older SD, and the micro SD ones.

Question about a login: what would be the benefit? If someone is able to plug the Arduino in to a serial port/USB, they have access to the local SD card, right? Unless you're mounting it in some sort of lock box?

yes i read it correctly and right now i solved the problem. The issue I encountered solved as I connect it with lack of force.

In

Im mounting it inside of our project and we want to store points of the user so he/she can claim it whenever the user wants and and the points will not lost as it saves on sd card

1 Like

I tried this one, but you didn't search for what string should be change.. you just state the location

The code wasn't meant to be a solution, just an example of how to change an entry.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.