Arduino Projects

How to Build an ESP32 RFID Cashless Payment System with Local Database and Admin Dashboard (Complete Project Guide)

Cashless payment technology has become an essential part of modern society. From public transportation and school cafeterias to supermarkets, offices, libraries, and access control systems, RFID-based payment solutions continue to replace traditional cash transactions because they are faster, safer, and easier to manage.

Most commercial RFID payment systems rely on cloud servers, internet connectivity, and expensive subscription services. While these solutions work well for large organizations, they are often unnecessary for small businesses, schools, transport operators, research laboratories, and educational projects that simply need a secure, reliable, and affordable local payment system.

In this project, I designed and built a complete ESP32 RFID Cashless Payment System capable of storing user information, processing account top-ups, deducting payments, checking balances, recording every transaction, and allowing an administrator to manage users through a local wireless dashboard—all without requiring an internet connection.

The entire system runs on the powerful ESP32 Development Board, uses the popular MFRC522 RFID Reader/Writer, stores information inside the ESP32 using SPIFFS, records accurate timestamps with the DS3231 Real-Time Clock (RTC), displays user information on a 16×2 I2C LCD, and creates its own Wi-Fi network where administrators can monitor accounts and export transaction history.

Unlike many RFID tutorials available online, this project goes far beyond simply reading an RFID card. It demonstrates how multiple embedded technologies can work together to build a practical electronic payment solution that closely resembles real-world systems used in transportation, campuses, event centers, and businesses.

Whether you are an engineering student, electronics enthusiast, IoT developer, embedded systems engineer, or final-year project researcher, this guide will provide valuable insight into designing a standalone RFID payment platform that is expandable and ready for further development.

Throughout this article, I will explain the complete design philosophy, the hardware used, how the software operates, how the local database works, how transaction records are stored, and how the ESP32 serves an administrator dashboard over a Local Area Network (LAN). I will also discuss how the Arduino code coordinates all of these components to create a responsive and reliable cashless payment system.

If you are looking for a practical ESP32 RFID project that combines embedded systems, data storage, web technologies, and wireless networking into one complete application, this project is an excellent place to start.

Project Overview

The primary objective of this project was to design a fully functional RFID-based electronic payment terminal capable of operating independently on a local wireless network without relying on cloud services or external databases.

The system allows authorized administrators to register RFID cards, remove users, recharge balances, deduct payments, verify account balances, and maintain a complete transaction history. Every operation is timestamped using a real-time clock and stored inside the ESP32’s internal flash memory for future reference.

RFID cashless payment system dashboard – The remote access dashboard

To make the system user-friendly, all interactions are displayed on a 16×2 LCD screen, while three navigation buttons provide an intuitive menu interface for selecting different administrative functions.

Unlike conventional Arduino RFID demonstrations that simply display a card’s UID on the Serial Monitor, this project introduces persistent storage, user authentication, account management, transaction logging, and a browser-based administrator interface.

One of the project’s most useful features is its built-in Wi-Fi Access Point. Instead of connecting to an existing router, the ESP32 creates its own wireless network. Once connected, an administrator can log into a password-protected web dashboard to view registered users, monitor balances, inspect transaction history, and export records in CSV format for further analysis using Microsoft Excel or other spreadsheet software.

The entire system was designed to operate as a portable embedded device powered by a rechargeable 3.7V lithium-polymer battery. A dedicated charging module continuously charges the battery whenever external 5V power is available, allowing uninterrupted operation even during charging. This makes the project suitable for portable installations where mobility and continuous uptime are important.

Because all information is stored locally within the ESP32 using SPIFFS, the system remains fully functional even when internet access is unavailable. This significantly improves reliability while reducing operational costs associated with cloud hosting and remote databases.

Key Features of the ESP32 RFID Cashless Payment System

This project incorporates several advanced features that make it significantly more capable than a standard RFID card reader.

RFID User Authentication

Every RFID tag or card possesses a unique identification number (UID). When a user scans a card, the ESP32 compares the UID against its locally stored database to determine whether the card is registered. Unauthorized cards are rejected immediately, helping to prevent unauthorized access.

Administrator Authentication

RFID tag with unique IUD

To enhance security, sensitive operations such as adding users, removing cards, topping up balances, debiting accounts, and checking balances require an administrator RFID card before access is granted.

This additional authentication layer helps protect the database from unauthorized modifications.

User Registration

New RFID cards can be enrolled directly from the device without connecting to a computer. Once authenticated as an administrator, a new card can be scanned and stored inside the onboard database with its own account information.

Balance Management

Each registered RFID card functions like a digital wallet.

Administrators can:

  • Increase account balance
  • Deduct payment amounts
  • View current balance
  • Store updated balances automatically

This functionality makes the project suitable for prepaid payment systems.

Local Database Storage

Local database storage on ESP32

Instead of relying on an online SQL database or cloud platform, all user information is stored inside the ESP32 using SPIFFS in JSON format.

This offers several advantages:

  • Offline operation
  • Faster data access
  • Reduced infrastructure cost
  • Increased portability
  • Easier deployment

Transaction History

Every successful debit or top-up operation is automatically recorded.

The stored information includes:

  • Date
  • Time
  • User ID
  • Transaction type
  • Transaction amount
  • Updated balance

Maintaining a transaction log improves accountability and simplifies auditing.

Real-Time Clock Integration

The RFID payment system showing time and date

The DS3231 Real-Time Clock ensures that every transaction receives an accurate timestamp even if the ESP32 restarts. Accurate timekeeping is especially important for payment systems because transaction records should always contain reliable dates and times.

LCD User Interface

A 16×2 I2C LCD provides immediate feedback during every operation.

Examples include:

  • Waiting for card
  • Administrator verification
  • Successful top-up
  • Balance display
  • Invalid card alerts
  • Payment confirmation

This improves the user experience while reducing confusion during operation.

Push Button Navigation

pushbutton controls for RFID payment system

Rather than requiring a computer or mobile application, the device includes three physical buttons for navigating the on-device menu.

The buttons perform the following functions:

  • Menu/Select: Enter menus and confirm actions.
  • Up/Increment: Navigate upward and increase values.
  • Down/Decrement: Navigate downward and decrease values.

This simple interface makes the system easy to operate even for users with little technical experience.

You Can Read Our other Related RFID Projects Like…

Built-In Wi-Fi Admin Dashboard

The ESP32 creates its own Wi-Fi hotspot, allowing administrators to connect directly using a smartphone, tablet, or laptop.

After logging in with administrator credentials, users can:

  • View registered RFID users
  • Monitor account balances
  • Inspect transaction history
  • Export payment records as CSV files
  • Manage the payment database without additional software

This built-in dashboard transforms the ESP32 from a simple embedded controller into a compact standalone management server.

Rechargeable Portable Design

The hardware was designed for portability and uninterrupted operation.

The system combines:

  • A 3.7V rechargeable LiPo battery
  • A LiPo charging module
  • A regulated 5V power supply

This arrangement enables the battery to charge while simultaneously powering the system, allowing continuous operation without shutting down during charging.

Such a design is ideal for portable ticketing terminals, mobile payment devices, temporary event installations, educational demonstrations, and remote deployments.

Hardware Components Used

The following hardware components were used to build the complete RFID payment system.

ComponentPurpose
ESP32 Development BoardMain controller and Wi-Fi server
MFRC522 RFID Reader/WriterReads RFID cards and tags
RFID Cards/TagsUser identification and payment medium
16×2 I2C LCD ModuleDisplays menus and transaction information
DS3231 RTC ModuleProvides accurate date and time
Three Push ButtonsMenu navigation and user input
3.7V LiPo BatteryPortable power source
LiPo Charging ModuleCharges the battery safely
5V 0.6A Power Supply ModuleExternal power and charging source
Jumper Wires and PCBElectrical connections and assembly

Project Demonstration

Front view of the RFID payment system design

The above image is the front view of the finished device. The 1602 LCD screen is palce at the transpparent cover top of the enclosure of the ESP32 RFID Cashless Payment System. As well as the RFID reader. This is most convinient to quickly scan the RFID cards or tags of the users. There is also an indicator LED that blinks for each action carried out byh the design.

ESP32 RFID Cashless Payment System- A new card being scanned

A close up picture of the RFID card being scanned is shown above. Before a new tag or existing card is being used in the design to carry out any transaction, the admin has to verify such a transaction by using his or her own tag. The image above is a new card being added to the system for a user. After this, the user’s card be topped up a certain amount.

The LCD displaying transaction messages. As soon as the trascations has been carried out, the result is shown on the LCd screen of the project design.

The navigation button

Menu navigation using the push buttons on the project allowed the admin to safely and conviniently select with option of decions he or she wants to make. In the image above, the nav button allowed the admin to debit a sum of 50 from the user’s card.

ESP32 RFID Cashless Payment System- The admin dashboard on a browser

The image above shows the Administrator dashboard open in a web browser. We can see the tabulated summary of every transactions performed by the project design. These include the how many users are registered in the system, their respeictive user ID, When they performed a transactions, what type of transaction was actually performed, their available balance and the date and time when the transaction occured.

Circuit Diagram

The schematic diagram of the ESP32 RFID Cashless Payment System.

Detailed Explanation of the Circuit Diagram

The above is the schematic diagram of the project. It is buit around the ESP32 development (dev.) board as the brain of the design. The RFID reader, MFRC522 is connected to the ESP32 using SPI communication.

The pushbuttons that served as the nav buttons were connected through push-up technique. This allowed us to make use of 3 pushbuttons with three (3) pieces of 10k-Ohms resistors to achieve this.

The LCD module of course was connected to the ESP32 using the I2C communication protocol. With the help of the I2C LCD module, we were able to reduce the number of the communication wires from 6 data wires to only 2. Using the SCL and the SDA this time.

Since the RTC module, DS3231 module also used the I2C communication protocol, it was connected likewise. However, since each I2C device has its addressable bus, this was easier to find and program it.

THe power to the system design came two ways: the utility source from the 5V Hi-link Power supply and the 3.7V 2000mAh rechargeable battery. The connection was done is such a way that the power supply can charge the battery by using the LiPO Battery charger module.

Lastly, a switch was added to ensure that the power is isolated from the design when needed. This is the pictorial view of the schematic diagram. The PCB is already completed and you can order it by following the link here.

How the ESP32 RFID Cashless Payment System Works

At a high level, the system follows a simple but robust workflow designed to ensure secure and traceable transactions.

When the device powers on, the ESP32 initializes all connected peripherals, including the RFID reader, LCD, RTC, Wi-Fi Access Point, SPIFFS storage, and local web server. Existing user records and transaction history are loaded from internal flash memory into RAM, allowing the system to resume operation with previously stored data.

In its idle state, the LCD continuously displays the current date and time obtained from the DS3231 RTC module. This provides visual confirmation that the device is active and that the internal clock is functioning correctly.

To perform administrative tasks, the administrator presses the menu button to enter the navigation interface. Using the Up and Down buttons, the desired operation—such as checking a balance, adding a new card, removing a card, topping up funds, or debiting an account—is selected and confirmed.

Before any sensitive operation proceeds, the system requires authentication using a predefined administrator RFID tag. This security step helps prevent unauthorized users from modifying account information or performing financial transactions.

Once authenticated, the ESP32 prompts for the appropriate RFID card. Depending on the selected operation, the software updates the user’s balance, saves the changes to the local JSON database stored in SPIFFS, records the transaction with an accurate timestamp from the RTC, and refreshes the LCD with confirmation messages.

At the same time, the ESP32 hosts a password-protected web dashboard over its built-in Wi-Fi Access Point. Administrators connected to this network can review registered users, inspect transaction history, and export all records in CSV format for reporting or backup purposes.

This combination of embedded hardware, local storage, and wireless administration results in a compact, standalone cashless payment solution that is practical, reliable, and easily expandable for real-world applications.

Hardware Components and System Design

Building an RFID cashless payment system is not simply a matter of connecting an RFID reader to an ESP32 and reading a card UID. To make the project useful as a complete embedded system, several different hardware modules have to work together.

The RFID reader identifies the user, the ESP32 processes the transaction, the LCD provides visual feedback, the push buttons provide a physical user interface, the RTC provides accurate timestamps, and the ESP32’s internal flash storage preserves account and transaction information.

The power system is equally important because this project was designed to operate as a portable rechargeable device while also supporting operation from an external 5V supply.

This section explains the major hardware components used in the project and how they fit into the overall system architecture.

ESP32 Development Board

At the center of the project is the ESP32 development board.

The ESP32 was selected as the main controller because it provides considerably more functionality than a basic Arduino board. In this project, the microcontroller is responsible for processing RFID cards, controlling the LCD, reading the push buttons, communicating with the DS3231 RTC, managing internal storage, hosting the local Wi-Fi network, and running the web server.

In other words, the ESP32 is responsible for both the embedded control system and the local network application.

This makes the ESP32 particularly suitable for projects that combine hardware and software.

Why use an ESP32?

One of the biggest advantages of the ESP32 in this project is its integrated Wi-Fi capability. A conventional Arduino Uno or Arduino Nano would require an additional Wi-Fi module if the project needed a wireless administrator dashboard. The ESP32 already contains Wi-Fi functionality, reducing the number of external components and simplifying the overall design.

The ESP32 also provides:

  • Multiple digital GPIO pins
  • SPI communication
  • I2C communication
  • UART interfaces
  • Wi-Fi connectivity
  • Significant processing capability
  • Internal flash storage
  • Support for web-server applications
  • Compatibility with the Arduino development environment

These features make it possible to combine several technologies into a single embedded platform.

MFRC522 RFID Reader/Writer

The MFRC522 RFID module is responsible for communicating with the RFID cards and tags used by the system. RFID stands for Radio Frequency Identification. It is a technology that allows information to be exchanged wirelessly between a reader and a compatible RFID tag or card.

In this project, the RFID card acts primarily as an identification token. When a card is placed close to the MFRC522 reader, the reader detects it and communicates with the card. The ESP32 then obtains the card’s UID and uses that identifier to determine which user account is associated with the card.

The important concept here is that the system does not need to store the user’s entire account information on the RFID card. Instead, the RFID card provides an identifier, while the actual account information is stored in the ESP32’s local database.

The basic relationship is therefore:

RFID Card → UID → ESP32 → Local User Database → Account Information

For example, the system might read a card UID such as:

5305F803

The ESP32 searches its locally stored user records for that UID. If the UID exists, the corresponding account can be accessed. If it does not exist, the system treats the card as unregistered. This approach makes the RFID card function similarly to an identification key.

RFID Card and User Identification

The RFID cards used in the project are associated with individual users. During registration, the administrator scans a new RFID card. The ESP32 reads its UID and stores that UID in the user database. The project uses a simple user structure:

struct User {
  String id;
  String name;
  int balance;
};

This structure associates three pieces of information with each user:

  • id — the RFID card UID
  • name — the user’s assigned name
  • balance — the user’s current account balance

For example, a record can conceptually look like this:

RFID UIDNameBalance
5305F803User1500

When that card is scanned later, the ESP32 can locate the corresponding user and retrieve the balance. This separation between the RFID identifier and the account data is an important part of the project’s architecture.

RFID Administrator Card

The project uses a special RFID card as the administrator credential.

The administrator card has a predefined UID in the program:

String admin = "1C13FF38";

Sensitive operations require the administrator to scan this card before the operation can continue.

For example, adding a new card follows a workflow similar to:

Select Add Card → Scan Administrator Card → Verify Admin → Scan New Card → Confirm → Save

The same principle is used for:

  • Removing a card
  • Topping up an account
  • Debiting an account
  • Checking a user’s balance

This provides an additional authentication layer at the physical device.

Important security consideration

The administrator UID is currently hard-coded into the Arduino program. That is acceptable for a prototype or educational project, but it should not be considered sufficient security for a commercial payment system.

A production implementation should consider stronger authentication mechanisms, secure credential storage, encrypted communication, protected administrative credentials, and potentially cryptographic authentication rather than relying only on a card UID. This distinction is important because a prototype can demonstrate the concept successfully while still requiring additional security engineering before handling real money or sensitive financial information.

16×2 I2C LCD Display

The project uses a 16×2 LCD module with an I2C interface as the primary local display. The LCD contains two rows, with each row capable of displaying up to 16 characters. The LCD is used to provide immediate feedback to the person operating the device.

For example, it can display messages such as:

  • Admin Auth Needed
  • Scan Admin Card...
  • Admin Verified!
  • Scan User Card...
  • Top-Up Success!
  • Debit Success!
  • Insufficient Funds!
  • Card Not Found
  • Card Removed!

This is particularly useful because the device does not need to remain connected to a computer for basic operation.

Why Use I2C for the LCD?

The I2C interface significantly reduces the number of ESP32 GPIO pins required by the LCD.

Instead of connecting many individual LCD control and data lines, the I2C backpack allows communication using the I2C bus.

The code initializes the LCD using:

LiquidCrystal_I2C lcd(0x27, 16, 2);

Here:

  • 0x27 is the I2C address configured for the LCD module.
  • 16 represents the number of columns.
  • 2 represents the number of rows.

The ESP32 initializes the I2C interface with:

Wire.begin(SDA_PIN, SCL_PIN);

In this project:

#define SDA_PIN 5
#define SCL_PIN 4

Therefore, GPIO 5 is used for SDA and GPIO 4 for SCL.

The I2C bus allows the ESP32 to communicate with the LCD and other compatible I2C devices.

DS3231 Real-Time Clock Module

The DS3231 RTC module is responsible for keeping track of the date and time.

This is particularly important for a payment or transaction-recording system because knowing what happened is not enough. The system should also know when it happened.

Every transaction recorded by the project contains:

  • Date
  • Time
  • User ID
  • Transaction type
  • Amount
  • New account balance

The RTC makes this possible.

The project creates the RTC object with:

RTC_DS3231 rtc;

During initialization, the program checks whether the RTC is available:

if (!rtc.begin()) {
  Serial.println("Couldn't find RTC");
  while (1);
}

The system also checks whether the RTC has lost power:

if (rtc.lostPower()) {
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}

This is useful when initially setting up the device, although a production system would ideally provide a more deliberate clock-setting mechanism.

Recording Transaction Date and Time

The project uses the following function to obtain the current date and time:

void getCurrentDateTime(String &dateStr, String &timeStr)

The function reads the current time from the RTC:

DateTime now = rtc.now();

It then creates formatted date and time strings.

For example, a transaction might eventually be represented as:

Date: 2026-09-27
Time: 13:06:25

This information is then stored with the transaction.

The result is a much more useful transaction history than simply recording the amount deducted.

Three Push Buttons

The device includes three physical push buttons.

They are connected to:

#define upPin  12
#define dwPin  14
#define sePin  27

The three buttons have different responsibilities.

Up Button

The Up button allows the operator to:

  • Move upward through menu options
  • Increase a top-up amount
  • Increase a debit amount
  • Select “Yes” during certain confirmation screens

Down Button

The Down button allows the operator to:

  • Move downward through menu options
  • Decrease a transaction amount
  • Select “No” during certain confirmation screens

Select Button

The Select button is used to:

  • Enter the menu
  • Select an operation
  • Confirm an amount

Together, these three buttons create a simple embedded user interface without requiring a touchscreen.

The On-Device Menu System

The menu is one of the features that turns the project from a basic RFID reader into a complete embedded application.

The software maintains a menu position using:

int menuOption = 0;

The available menu options are:

  1. Check Balance
  2. Add Card
  3. Remove Card
  4. Top-Up Card
  5. Debit Card

The LCD displays two menu items at a time.

For example:

>Check Balance
 Add Card

Pressing the Up or Down button moves through the options. The greater-than symbol indicates the currently selected option. This creates a basic menu navigation system similar to what can be found in dedicated electronic terminals.

SPI Communication

The MFRC522 RFID reader communicates with the ESP32 using the SPI communication protocol.

The project initializes SPI with:

SPI.begin();

The RFID reader is then initialized using:

rfid.PCD_Init();

The MFRC522 object is created using:

MFRC522 rfid(SS_PIN, RST_PIN);

with:

#define SS_PIN 21
#define RST_PIN 22

This allows the ESP32 to communicate with the RFID reader and retrieve card information.

The project therefore uses two important communication protocols:

I2C

Used for:

  • LCD
  • DS3231 RTC

SPI

Used for:

  • MFRC522 RFID reader

This is a good example of how an ESP32 can coordinate several peripheral devices using different communication protocols.

SPIFFS: Local Storage Inside the ESP32

One of the most interesting parts of this project is that it does not depend on an external database server to store its information. Instead, the ESP32 uses SPIFFS, which stands for Serial Peripheral Interface Flash File System. SPIFFS allows the ESP32 to use part of its internal flash memory as a file system.

The project uses SPIFFS for two major purposes:

  1. Storing user account information.
  2. Storing transaction history.

The system creates two important files:

/users.json
/transactions.json

This gives the project persistent storage. Without persistent storage, information stored only in RAM would normally disappear when the ESP32 loses power or restarts. By saving the data to flash, the system can reload the information when it starts again.

JSON as the Local Database Format

The project uses JSON to organize its stored information. JSON stands for JavaScript Object Notation. It is a lightweight text-based format commonly used for exchanging and storing structured data.

The ArduinoJson library is included in the project:

#include <ArduinoJson.h>

The user database is stored in a structure similar to:

{
  "users": [
    {
      "id": "5305F803",
      "name": "User1",
      "balance": 500
    }
  ]
}

This is particularly useful because the data is human-readable and easy to process programmatically. The transaction database follows a similar concept.

For example, a transaction record contains:

{
  "date": "2026-09-27",
  "time": "13:06:25",
  "userId": "5305F803",
  "type": "DEBIT",
  "amount": 50,
  "newBalance": 450
}

The combination of ESP32 + SPIFFS + JSON effectively creates a small embedded local database system.

User Database Structure

The project defines:

const int MAX_USERS = 3;

This means the prototype can store up to three registered users.

The initial user database is defined as:

User users[MAX_USERS] = {
  {"5305F803", "User1", 0},
  {"", "", 0},
  {"", "", 0}
};

The first user is already defined, while the other two positions are empty. This limit was intentionally kept small for the prototype. A future version could replace the fixed-size array with a more scalable storage architecture.

For example, a production system could use:

  • An external SD card
  • External EEPROM
  • An external database server
  • SQLite
  • MySQL
  • PostgreSQL
  • A cloud database
  • An API connected to a backend server

The current implementation is therefore best understood as a local embedded database prototype rather than a commercial banking database.

Transaction Database

The project also defines:

const int MAX_TRANSACTIONS = 50;

This means the prototype can store up to 50 transaction records in its in-memory transaction array.

Each transaction is represented by:

struct Transaction {
  String date;
  String time;
  String userId;
  String type;
  int amount;
  int newBalance;
};

The transaction type can be:

TOPUP

or:

DEBIT

This allows the administrator to determine whether money was added to or deducted from an account.

How a Top-Up Transaction Works

A top-up increases the user’s account balance.

The workflow is approximately:

Administrator Authentication

↓

Scan User RFID Card

↓

Locate User Account

↓

Select Top-Up Amount

↓

Confirm Transaction

↓

Increase Balance

↓

Create Transaction Record

↓

Save User Database

↓

Save Transaction History

↓

Display Success Message

The top-up amount starts at:

int amount = 50;

The Up button increases the amount by 50:

amount += 50;

The Down button decreases it by 50, provided the amount remains above the minimum:

if (amount > 50) {
  amount -= 50;
}

This gives the operator a simple way to select the transaction amount.

How a Debit Transaction Works

A debit transaction performs the opposite operation. The system first authenticates the administrator and identifies the user. It then asks the operator to select the amount to deduct.

Before completing the transaction, the software checks the user’s balance:

if (users[userIndex].balance < amount)

If the balance is insufficient, the system displays:

Insufficient
Funds!

and cancels the transaction. This is an important part of the payment logic because it prevents the account from being reduced below zero.

If sufficient funds are available, the system subtracts the amount:

users[userIndex].balance -= amount;

The transaction is then added to the transaction history and both databases are saved.

Local Wi-Fi Access Point

One of the most useful features of this project is the ESP32’s ability to create its own Wi-Fi network.

The project uses:

WiFi.softAP(ssid, password);

The network is configured using:

const char* ssid = "ESP32-Admin";
const char* password = "admin1234";

This means an administrator does not need to connect the device to an existing home or office Wi-Fi router. Instead, the ESP32 itself becomes the access point.

A typical workflow is:

ESP32 powers on

↓

ESP32 creates Wi-Fi network

↓

Administrator connects phone/laptop to ESP32-Admin

↓

Administrator opens the ESP32 web interface

↓

Administrator logs in

↓

Dashboard displays account and transaction information

This is particularly useful for portable installations.

Embedded Web Server

The project uses the ESP32’s built-in networking capabilities to host a web server.

The following object creates the server:

WebServer server(80);

Port 80 is the standard HTTP port. The program then defines several routes.

For example:

server.on("/", handleRoot);

The root page redirects the administrator to the login page.

The login route is:

server.on("/login", HTTP_GET, []() {
  handleLogin();
});

The dashboard is served through:

server.on("/dashboard.html", handleDashboard);

The system also provides an export route:

server.on("/export", handleExport);

These routes allow the ESP32 to behave like a small standalone web server.

Administrator Web Dashboard

The web dashboard provides another way of interacting with the system. While the physical buttons and LCD are used to operate the embedded device, the web dashboard is intended for administration and monitoring.

The dashboard displays a user table containing:

  • User ID
  • Name
  • Balance

It also displays the transaction history containing:

  • Date
  • Time
  • User ID
  • Transaction type
  • Amount
  • New balance

This provides a much larger view of the information than the 16×2 LCD can provide. The dashboard therefore complements rather than replaces the physical interface.

CSV Data Export

The project also includes an export function. When the administrator selects the export option, the ESP32 creates CSV-formatted data.

CSV stands for Comma-Separated Values. The exported information can be opened using applications such as:

  • Microsoft Excel
  • Google Sheets
  • LibreOffice Calc
  • Other spreadsheet applications

The code creates the CSV header:

User ID,Name,Balance

followed by the account records.

The transaction section contains:

Date,Time,User ID,Type,Amount,New Balance

This is a useful feature because it allows information stored inside the embedded device to be transferred into a more powerful data-analysis environment.

For example, an administrator could export a month’s transaction records and use Excel to calculate:

  • Total top-ups
  • Total debits
  • Number of transactions
  • Individual user activity
  • Remaining balances
  • Transaction frequency

Rechargeable Power System

Portability was another important consideration in the design. The project uses a 3.7V LiPo rechargeable battery as its portable power source. A LiPo battery provides a relatively compact source of rechargeable energy, making it suitable for portable electronics.

However, a LiPo cell should not simply be connected directly to every part of an embedded system. The battery requires appropriate charging and power regulation. That is why the project incorporates a LiPo charging module and a regulated external 5V supply.

LiPo Charging Module

The charging module is responsible for managing the charging process of the 3.7V LiPo battery. When an external 5V supply is connected, the charging circuit can charge the battery while the system is powered. This creates a convenient operating mode in which the device can remain connected to utility power while simultaneously maintaining the battery.

The general power flow is:

5V External Supply

↓

LiPo Charging Module

↓

3.7V LiPo Battery

↓

Power Regulation / System Supply

↓

ESP32 + Peripherals

The exact electrical arrangement should follow the specifications of the charging and regulation modules actually used in the hardware.

Utility Power Operation

The project also includes a 5V 0.6A power supply. This allows the system to operate from an external utility-powered source instead of depending exclusively on the battery. When external power is available, the system can operate continuously while the battery is charged by the charging circuit.

This provides two important operating modes:

Portable Mode

The system operates from the LiPo battery.

External Power Mode

The system operates from the external 5V supply while the rechargeable battery is maintained through the charging circuit. This makes the device more flexible than a battery-only design.

Complete System Workflow

The complete operating sequence can be summarized as follows.

Step 1: Power On

The ESP32 starts and initializes the connected hardware.

Step 2: Initialize Storage

SPIFFS is mounted and existing user and transaction files are loaded.

Step 3: Initialize RFID

The MFRC522 reader is initialized so that cards can be detected.

Step 4: Initialize RTC

The DS3231 is checked and prepared for timekeeping.

Step 5: Start Wi-Fi

The ESP32 creates its own wireless access point.

Step 6: Start Web Server

The local administration interface becomes available.

Step 7: Display Date and Time

The LCD enters its normal idle state.

Step 8: Enter Menu

The administrator presses the Select button.

Step 9: Select Operation

The Up and Down buttons are used to navigate through the menu.

Step 10: Authenticate Administrator

The administrator scans the authorized RFID card.

Step 11: Perform Operation

Depending on the selected menu option, the administrator can:

  • Check a balance
  • Add a card
  • Remove a card
  • Top up an account
  • Debit an account

Step 12: Update Database

The user account is updated.

Step 13: Record Transaction

For financial operations, the system records the transaction date, time, amount, type, and resulting balance.

Step 14: Save Data

The updated information is written to SPIFFS.

Step 15: Display Result

The LCD displays the result of the operation.

At the same time, the administrator can connect to the ESP32’s local Wi-Fi network and inspect the stored information from the web dashboard.

Hardware Architecture at a Glance

The architecture of the project can be represented conceptually as:

hardware architecutre of the RFID payment system design

This architecture demonstrates how the project combines RFID, embedded processing, local storage, real-time clock functionality, wireless networking, web technology, and rechargeable power management into one system.

Why This Architecture Is Useful

One of the major strengths of this project is that the different technologies have clearly defined responsibilities. The RFID reader does not need to know anything about account balances. The LCD does not need to know how transactions are stored. The RTC does not need to know how the web dashboard works. The web server does not directly control the RFID hardware.

Instead, the ESP32 acts as the central coordinator. This separation makes the project easier to understand and provides a foundation for future improvements. For example, the RFID component could eventually be replaced with another identification technology while keeping much of the account-management software intact. Similarly, SPIFFS could eventually be replaced with an external database without completely redesigning the user interface.

Hardware Summary

The hardware design can therefore be summarized as follows:

HardwareMain Function
ESP32Central controller, Wi-Fi and web server
MFRC522RFID card/tag reader
RFID CardUser identification
16×2 I2C LCDLocal display
DS3231Real-time clock
Up ButtonNavigation/increment
Down ButtonNavigation/decrement
Select ButtonMenu selection/confirmation
SPIFFSLocal flash file storage
LiPo BatteryPortable power
LiPo ChargerBattery charging
5V SupplyExternal power source

The result is a compact embedded platform capable of performing significantly more than basic RFID card detection.

Software Architecture of the RFID Payment System

The Arduino program can be divided into several major software sections.

These include:

  1. Library initialization
  2. Hardware configuration
  3. RFID card detection
  4. User database management
  5. Transaction management
  6. Real-time clock management
  7. Menu navigation
  8. Administrator authentication
  9. Top-up operations
  10. Debit operations
  11. Local Wi-Fi configuration
  12. Web server and dashboard
  13. CSV data export
  14. Main program loop

Each section has a specific responsibility, while the ESP32 coordinates the entire application.

Libraries Used in the Project

The project uses several Arduino libraries to communicate with the different hardware and software components.

The main libraries include:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
#include <SPI.h>
#include <MFRC522.h>
#include <SPIFFS.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <WebServer.h>

Each library has a specific purpose.

Wire.h

The Wire library provides I2C communication. It is used for communicating with the LCD and DS3231 RTC.

LiquidCrystal_I2C.h

This library provides control of the 16×2 I2C LCD.

RTClib.h

This library provides functions for communicating with the DS3231 real-time clock.

SPI.h

The SPI library provides the communication interface required by the MFRC522 RFID module.

MFRC522.h

This library makes it easier to detect RFID cards and retrieve their UIDs.

SPIFFS.h

SPIFFS provides access to the ESP32’s internal flash file system.

ArduinoJson.h

ArduinoJson is used to create, save, read, and parse JSON-formatted user and transaction data.

WiFi.h

This library provides the ESP32’s Wi-Fi functionality.

WebServer.h

This library allows the ESP32 to host the local administrator web interface. Together, these libraries provide the software foundation for the entire project.

Initializing the Hardware

The setup() function is executed once whenever the ESP32 starts.

The program initializes the I2C interface:

Wire.begin(SDA_PIN, SCL_PIN);

The Serial Monitor is also started:

Serial.begin(9600);

The LCD is initialized:

lcd.init();

SPI communication is started:

SPI.begin();

The RFID reader is initialized:

rfid.PCD_Init();

The push-button pins are then configured. The program also initializes SPIFFS and starts the web server. Finally, it loads the previously saved user and transaction databases. This initialization process is important because all of the system’s components must be ready before the device begins processing transactions.

Reading RFID Cards

One of the most important functions in the project is the RFID reading process.

The program first checks whether a new RFID card is present:

rfid.PICC_IsNewCardPresent()

It then attempts to read the card:

rfid.PICC_ReadCardSerial()

Once the card has been successfully detected, the program extracts its UID. The readCardUID() function converts the RFID UID into a readable hexadecimal string.

For example:

5305F803

The UID is converted to uppercase before being returned. This UID becomes the primary identifier used by the local user database.

Finding a User from an RFID UID

Once the ESP32 obtains the RFID UID, the program searches through the user array.

Conceptually, the process is:

RFID Card
     ↓
Read UID
     ↓
Search User Database
     ↓
UID Found?
   ↙     ↘
 YES      NO
 ↓        ↓
Load     Reject
Account  Card

If the UID matches a registered user, the system can retrieve the person’s name and current balance.

If there is no matching UID, the system displays a message such as:

User Not Found!

This prevents an unknown RFID card from being used as a registered account.

Adding a New RFID Card

The addToDataBase() function handles user registration. Before adding a card, the system requires administrator authentication.

The LCD displays:

Admin Auth Needed
Scan Admin Card...

The administrator then scans the authorized RFID card.

If the UID matches the stored administrator UID, the system displays:

Admin Verified!

The new RFID card can then be scanned. The software checks whether that card already exists in the database. If it already exists, the registration process is cancelled. If the card is new, the administrator is asked to confirm the registration. Once confirmed, the card is assigned a user record and its initial balance is set to zero.

The updated user database is then saved to SPIFFS.

Removing an RFID Card

The removeFromDataBase() function performs the opposite operation. Again, administrator authentication is required before the operation can proceed. The administrator scans the card that should be removed. The program searches the database for the corresponding UID. If the card exists, its user record is cleared and the updated database is saved. The program also contains an important protection mechanism that prevents the administrator card from being removed as an ordinary user card. This is a simple but useful security measure in the prototype.

Checking an Account Balance

The checkAccountBalance() function allows an administrator to check the balance associated with an RFID card.

The process is:

Authenticate Administrator
↓
Scan User Card
↓
Find User
↓
Read Balance
↓
Display Balance

The LCD displays the user’s name and current balance.

For example:

User: User1
Balance: 500

This provides a convenient way to verify an account without accessing the web dashboard.

Adding Money Through Top-Up

The topUpAccount() function increases a user’s account balance. The administrator must first authenticate using the administrator RFID card. The user card is then scanned. After the account is located, the operator selects the amount to add. The prototype starts with an amount of 50 and allows the Up and Down buttons to increase or decrease the amount in increments of 50. The Select button confirms the amount. The system then asks for a final confirmation before changing the account balance.

If confirmed, the program executes:

users[userIndex].balance += amount;

The new balance is then saved. A transaction record is also created.

Debiting an Account

The debitAmount() function is responsible for deducting money from a user’s account. The administrator is authenticated first, followed by the user’s RFID card. The operator then selects the amount to deduct. Before completing the transaction, the program checks whether the user has enough balance.

The important check is:

if (users[userIndex].balance < amount)

If the balance is insufficient, the system displays:

Insufficient
Funds!

and does not perform the transaction.

If there is sufficient balance, the amount is deducted:

users[userIndex].balance -= amount;

The new balance is then saved together with the transaction record.

This simple balance validation is one of the most important parts of the payment logic.

Transaction History

The system does not only update balances. It also keeps a record of financial operations.

Each transaction contains:

struct Transaction {
  String date;
  String time;
  String userId;
  String type;
  int amount;
  int newBalance;
};

This means the system can determine:

  • When the transaction occurred
  • Which RFID account was involved
  • Whether it was a top-up or debit
  • How much money was involved
  • What the user’s balance became afterward

This makes the project more useful for auditing and record keeping.

Saving Data to SPIFFS

After an important database operation, the software saves the information to ESP32 flash storage.

The user database is stored as:

/users.json

while transaction history is stored as:

/transactions.json

The saveUserDatabase() function converts the user information into JSON and writes it to the file. The loadUserDatabase() function performs the reverse process when the ESP32 starts. The same principle is applied to transaction history. This means that the information is not dependent solely on RAM.

If the ESP32 is restarted, the program can reload the previously stored information.

Why Persistent Storage Matters

Imagine topping up an account and then switching off the ESP32. If the balance existed only in RAM, the information could be lost. By saving the information to SPIFFS, the system can restore the account information after restarting.

The basic process is:

Transaction
    ↓
Update RAM
    ↓
Save JSON
    ↓
SPIFFS Flash
    ↓
ESP32 Restart
    ↓
Read JSON
    ↓
Restore Database

This is one of the features that separates this project from a basic RFID demonstration.

Recording Accurate Transaction Time

Whenever a top-up or debit occurs, the program calls:

getCurrentDateTime(date, time);

The function obtains the current date and time from the DS3231 RTC. The information is then stored with the transaction.

For example:

Date: 2026-09-27
Time: 13:06:25
User ID: 5305F803
Type: DEBIT
Amount: 50
New Balance: 450

Having timestamps makes the transaction history much more meaningful.

The ESP32 Local Web Server

Another major part of the project is the local web server.

The ESP32 creates a Wi-Fi Access Point using:

WiFi.softAP(ssid, password);

The administrator can connect directly to this network.

The ESP32 then hosts the administration interface using:

WebServer server(80);

This means the system does not require an external internet connection to access the dashboard. The network is essentially a small private network created by the payment terminal itself.

Administrator Login

The web interface includes administrator authentication. The program defines administrator credentials and checks them before providing access to protected information.

The dashboard itself also uses:

server.authenticate(webUsername, webPassword)

To protect the dashboard and data export functions. This prevents an ordinary user connected to the ESP32’s Wi-Fi network from immediately accessing the transaction database. Again, this is appropriate for a prototype, but a production implementation should use stronger authentication and secure credential management.

The Web Dashboard

After authentication, the administrator can access the dashboard. The dashboard presents two important categories of information.

User Accounts

The system displays:

  • User ID
  • Name
  • Balance

Transaction History

The system displays:

  • Date
  • Time
  • User ID
  • Transaction type
  • Amount
  • New balance

This provides a convenient overview of the system without requiring the administrator to interact with the LCD and physical buttons for every administrative task.

Exporting the Database

The project also provides an export function. The administrator can select the export option from the web dashboard. The ESP32 generates a CSV file containing the user accounts and transaction history. The exported file can then be opened in spreadsheet software.

This is particularly useful for:

  • Accounting
  • Reporting
  • Data analysis
  • Backup
  • Record keeping
  • Demonstration purposes

It also provides a bridge between the embedded system and desktop data-processing tools.

Practical Applications of This Project Design

Although this particular implementation was developed as a prototype, the underlying concept can be adapted to several applications.

RFID Bus Ticketing

The system can be developed into a prepaid bus or transport ticketing platform where passengers use RFID cards to pay fares. A conductor or transport administrator could manage cards and balances locally.

School or University Payment Systems

RFID cards could potentially be used for controlled payments in:

  • School cafeterias
  • Student services
  • Campus transportation
  • Event centers

Employee Cafeteria Systems

Companies could issue RFID cards to employees and use a prepaid account system for cafeteria purchases.

Event Ticketing

Temporary events could use RFID cards to manage access or prepaid purchases without requiring a permanent internet connection.

Small Business Cashless Systems

Small businesses could potentially use a similar architecture for closed-loop prepaid transactions.

Laboratory and Educational Demonstrations

The project is also highly suitable for teaching:

  • Embedded programming
  • RFID technology
  • ESP32 development
  • Local networking
  • Database concepts
  • IoT architecture
  • Web-server development

Advantages of the Project Design

The design provides several advantages.

Offline Operation

The basic payment and database functions do not depend on the internet.

Portable

The rechargeable battery allows the device to operate away from a fixed power source.

Local Data Storage

User accounts and transaction records are stored directly on the ESP32.

Wireless Administration

Administrators can access the system through Wi-Fi.

Web-Based Dashboard

No dedicated desktop application is required to view the records.

CSV Export

Transaction data can be transferred to spreadsheet applications.

Simple User Interface

The LCD and three push buttons provide direct interaction with the device.

Expandable Architecture

The prototype can be extended with additional hardware and software features.

Limitations of the Current Prototype

Every prototype has limitations, and documenting them is important. The current implementation is intentionally limited to a small number of users and transactions.

The code defines:

const int MAX_USERS = 3;

and:

const int MAX_TRANSACTIONS = 50;

These limits make the prototype easier to manage but would need to be redesigned for a larger deployment. The system also uses relatively simple administrator authentication. The web credentials and administrator RFID UID are defined directly in the program. This is convenient during development but is not the recommended approach for a commercial financial system.

Another consideration is the use of ESP32 flash storage for transaction data. Flash memory has finite write endurance, so a larger production system should carefully manage how frequently data is written. The project also does not currently provide a sophisticated mechanism for recovering from corrupted database files or interrupted writes. These limitations do not diminish the value of the project as an embedded-system prototype. Instead, they provide clear opportunities for future development.

Future Improvements

There are many ways this project could be taken further.

Increase the Number of Users

The fixed three-user database could be replaced with a scalable database architecture.

Increase Transaction Capacity

The transaction history could be moved to an SD card or external database.

Add an Online Backend

A future version could synchronize transactions with a remote server whenever internet connectivity is available.

Add Mobile Application Support

A mobile application could be developed for monitoring balances and transaction history.

Improve Security

Future versions could implement stronger authentication and cryptographic security.

Add Multiple Payment Terminals

Several ESP32 terminals could potentially communicate with a central server.

Add Automatic Synchronization

A distributed system could synchronize local transactions when network connectivity becomes available.

Add QR Code Support

QR codes could be integrated alongside RFID cards.

Add NFC Smartphone Support

The system could potentially be extended to work with compatible NFC devices.

Add Printer Support

A thermal printer could be added to produce physical transaction receipts.

Add Battery Monitoring

The ESP32 could monitor battery voltage and display remaining battery status.

Add Data Backup

Automatic backups could be implemented to protect transaction records. These improvements could transform the prototype into a much more sophisticated IoT payment platform.

Important Note About Real-World Payments

This project demonstrates the technical concept of an RFID-based closed-loop cashless transaction system. It should not be confused with a commercial bank-card payment terminal. A production financial payment system would require substantially more security, reliability, compliance, authentication, encryption, auditing, and financial infrastructure.

For that reason, this project is best viewed as an educational and engineering prototype that demonstrates how RFID identification can be combined with local account management and transaction recording.

Conclusion

This ESP32 RFID cashless payment system demonstrates how several technologies can be integrated into a single practical embedded project. At the heart of the system is the ESP32, which acts as the central controller and local wireless server. The MFRC522 RFID reader provides card identification, while the RFID UID is used to locate the corresponding user account. The 16×2 I2C LCD provides immediate feedback, and the three push buttons create a simple menu-driven interface. The DS3231 RTC supplies accurate timestamps for transaction records, while SPIFFS and JSON provide a lightweight local storage mechanism for user accounts and transaction history.

The ESP32’s built-in Wi-Fi functionality adds another important dimension to the project. Instead of requiring an external router or internet connection, the ESP32 creates its own Wi-Fi network and hosts an administrator dashboard. Through this dashboard, an authorized administrator can view registered users, monitor balances, inspect transaction history, and export records as CSV data. The rechargeable 3.7V LiPo battery and external 5V power arrangement also make the design suitable for portable operation.

What makes this project particularly valuable is not any single component. The real value comes from the integration of hardware, software, storage, networking, and user-interface design. A simple RFID reader has been transformed into a complete embedded transaction-management platform. The project also provides a strong foundation for future development. With improved database architecture, stronger security, expanded storage, mobile applications, cloud synchronization, battery monitoring, multiple terminals, and more sophisticated authentication, the same fundamental concept could evolve into a considerably more advanced system.

For anyone learning embedded systems, ESP32 programming, RFID technology, IoT development, or hardware-software integration, this project demonstrates an important lesson:

A successful embedded project is not just about making individual components work. It is about making those components work together to solve a practical problem.

That is the central idea behind this ESP32 RFID cashless payment system.

Frequently Asked Questions

Can the ESP32 RFID payment system work without the internet?

Yes. The core RFID, balance-management, transaction-recording, LCD, RTC, and local database functions operate locally on the ESP32. The device also creates its own Wi-Fi Access Point for local administration.

What RFID reader is used in this project?

The project uses the MFRC522 RFID reader/writer module.

What microcontroller is used?

The main controller is an ESP32 development board.

Where is the payment data stored?

User accounts and transaction history are stored locally in the ESP32’s flash storage using SPIFFS and JSON files.

Can the transaction records be exported?

Yes. The administrator dashboard provides a CSV export function.

Can the project run from a battery?

Yes. The design incorporates a rechargeable 3.7V LiPo battery and charging circuit.

Can the system work while charging?

The project was designed to support operation from an external 5V supply while the LiPo battery is being charged, subject to the specifications and wiring of the particular charging and power-management modules used.

How many users does the current code support?

The prototype defines a maximum of three users:

const int MAX_USERS = 3;

This can be increased or redesigned for a larger database.

How many transactions can it store?

The current prototype defines:

const int MAX_TRANSACTIONS = 50;

A future version could use external storage or a server-based database for significantly larger transaction histories.

Can this project be used for real money?

The current design should be regarded as a prototype and educational project. A commercial system handling real financial transactions would require substantially stronger security, data integrity, authentication, reliability, and regulatory considerations.

Final Thoughts

This project started with a simple idea: use an RFID card to identify a user and allow that user to perform cashless transactions. By combining the MFRC522 RFID reader, ESP32, LCD, push buttons, DS3231 RTC, SPIFFS, JSON, Wi-Fi, and a local web server, that idea became a complete working embedded-system prototype. It demonstrates how modern embedded platforms can combine physical hardware with software and networking to create practical solutions.

The project can also serve as a foundation for much larger systems, including RFID bus ticketing, campus payment systems, event management, employee cafeteria systems, prepaid services, and other closed-loop payment applications. Most importantly, it demonstrates the process of moving from individual components to a complete product concept—one of the most important skills in embedded systems and IoT development.

smartechlabs

Recent Posts

How to Build an Arduino Igbo Market Day Display with P10 LED Panels

https://youtu.be/rnfi3aCiNXk If you grew up in Igboland, you already know that the week doesn't always…

4 weeks ago

AI-Powered Mycoprotein: Optimizing Conditions for Growing Sustainable Protein from Fungi.

Introduction: Can Fungi Really Feed the Future? Mycoprotein When people first hear about protein made…

8 months ago

Creating a Peer-to-Piece Tech Tool Library for a Neighborhood or Community.

Introduction Imagine this: your neighbor needs a 3D printer for a weekend project, while you’ve…

8 months ago

Becoming a “Sensor Network” Installer for Small Farms or Environmental Monitoring.

Introduction Imagine walking onto a small farm or a nature reserve, where tiny devices quietly…

8 months ago

The Personalized Children’s Book Creator: Using AI to Generate Stories Featuring the Child as the Hero.

Introduction Imagine handing your child an Interactive Personalized Storybook where they are the hero of…

8 months ago

Offering a “Disaster Recovery Drill” Service to Test a Company’s backups and restore processes.

Introduction Imagine waking up one morning to find your company’s entire IT infrastructure compromised—servers down,…

8 months ago

This website uses cookies.