Skip to content

15. System Integration

Assignment:

Individual assignment:

  • Design and document the system integration for your final project.

Your project should demonstrate how all the modules developed during the Fab Academy work together as a unified system, including:

  • 2D and 3D design
  • Additive and subtractive fabrication processes
  • Electronics design and production
  • Embedded microcontroller interfacing and programming
  • System integration and packaging

Project Introduction

This week, the objective is to bring together all the components developed throughout the Fab Academy into a single, functional and integrated system.

My final project is an RFID Access Control System for the FabLab. The system is designed to solve a real problem observed at our FabLab: the physical key was frequently unavailable or lost, and there was no reliable way to track who entered the lab and at what time.

The integrated system includes:

  • An RFID badge reader to identify users
  • An ESP32 microcontroller as the central processing unit
  • A 20x4 LCD screen to display information in real time
  • A servo motor to control the door lock mechanism
  • LEDs and a buzzer for visual and audio feedback
  • A web-based management application for remote monitoring and administration of access logs

System Architecture

Global Architecture Diagram

The diagram below presents the overall architecture of the system, showing how all components interact with each other:

PCB


System Integration Steps

Step 1 — Electronics Integration

The custom PCB designed during Week 6 (Electronics Design) and produced during Week 8 (Electronics Production) serves as the central hub of the system.

All components are connected to the ESP32 through the PCB:

Component ESP32 GPIO Protocol
RFID RC522 (SDA) GPIO 5 SPI
RFID RC522 (SCK) GPIO 18 SPI
RFID RC522 (MOSI) GPIO 23 SPI
RFID RC522 (MISO) GPIO 19 SPI
RFID RC522 (RST) GPIO 4 Digital
LCD 20x4 (SDA) GPIO 21 I2C
LCD 20x4 (SCL) GPIO 22 I2C
Servo Motor GPIO 13 PWM
LED Green GPIO 25 Digital
LED Red GPIO 26 Digital
LED Orange GPIO 26 Digital
Buzzer GPIO 27 Digital

PCB integration photo


Step 2 — Mechanical Integration (Packaging)

The 3D-printed enclosure designed with Fusion 360 and printed on the Prusa i3 MK3S+ during Week 5 (3D Scanning and Printing) houses all the electronic components.

The enclosure was designed to:

  • Fix the PCB securely using 4 mounting standoffs (M3)
  • Route wires cleanly to avoid shorts or strain on connectors
  • Expose the RFID reader flush with the front face for easy badge scanning
  • Provide clear visibility of the LCD screen through a dedicated window
  • Allow easy access to the USB port for firmware updates

Enclosure assembly photo


Step 3 — Firmware Integration

The embedded firmware was developed using Arduino IDE / PlatformIO (from Week 4 - Embedded Programming and Week 11 - Networking and Communications).

The firmware manages all components simultaneously using a non-blocking architecture based on millis() timers to avoid delays in execution.

Firmware Architecture

void loop() {

    // 1. Check RFID reader for new badge scan
    checkRFID();

    // 2. Update LCD display content
    updateDisplay();

    // 3. Control servo motor (door lock)
    updateDoorLock();

    // 4. Handle Wi-Fi and WebSocket communication
    handleWebSocket();

    // 5. Update LEDs and buzzer
    updateFeedback();
}

RFID Badge Identification Logic

When a badge is presented to the reader, the firmware:

  1. Reads the UID (Unique Identifier) of the badge via SPI
  2. Compares it against the list of authorized UIDs stored in memory
  3. Triggers the appropriate action:
  4. Authorized badge → Green LED ON, buzzer short beep, servo opens the lock, LCD displays "Access Granted"
  5. Unknown badge → Red LED ON, buzzer long beep, door remains locked, LCD displays "Access Denied"
  6. Logs the event (UID, timestamp, access result) and sends it via WebSocket to the admin dashboard

Complete Firmware Code

access_control.ino
#include <WiFi.h>
#include <WebSocketsServer.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>

// ========================== NETWORK CONFIGURATION ==========================
const char* SSID_WIFI = "YOUR_SSID";
const char* PASS_WIFI = "YOUR_PASSWORD";

// ========================== PIN CONFIGURATION ==========================
#define PIN_RFID_SDA    5
#define PIN_RFID_RST    4
#define PIN_SERVO       13
#define PIN_LED_GREEN   25
#define PIN_LED_RED     26
#define PIN_BUZZER      27

// ========================== GLOBAL OBJECTS ==========================
MFRC522 rfid(PIN_RFID_SDA, PIN_RFID_RST);
LiquidCrystal_I2C lcd(0x27, 20, 4);
Servo doorServo;
WebSocketsServer webSocket = WebSocketsServer(81);

// ========================== AUTHORIZED BADGE LIST ==========================
String authorizedUIDs[] = {
    "A1B2C3D4",
    "12345678"
};
int authorizedCount = 2;

// ========================== TIMING VARIABLES ==========================
unsigned long lastDoorOpen = 0;
bool doorIsOpen = false;
#define DOOR_OPEN_DURATION 5000  // Door stays open 5 seconds

// ========================== FUNCTIONS ==========================
String getUID(MFRC522 &reader) {
    String uid = "";
    for (byte i = 0; i < reader.uid.size; i++) {
        if (reader.uid.uidByte[i] < 0x10) uid += "0";
        uid += String(reader.uid.uidByte[i], HEX);
    }
    uid.toUpperCase();
    return uid;
}

bool isAuthorized(String uid) {
    for (int i = 0; i < authorizedCount; i++) {
        if (authorizedUIDs[i] == uid) return true;
    }
    return false;
}

void grantAccess(String uid) {
    // Visual and audio feedback
    digitalWrite(PIN_LED_GREEN, HIGH);
    digitalWrite(PIN_LED_RED, LOW);
    tone(PIN_BUZZER, 1000, 200);

    // Open the door lock
    doorServo.write(90);
    doorIsOpen = true;
    lastDoorOpen = millis();

    // Update LCD
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("  ACCESS GRANTED  ");
    lcd.setCursor(0, 1);
    lcd.print("UID: " + uid);
    lcd.setCursor(0, 2);
    lcd.print("Door: OPEN");

    // Send log to dashboard
    sendLog(uid, "GRANTED");
}

void denyAccess(String uid) {
    // Visual and audio feedback
    digitalWrite(PIN_LED_GREEN, LOW);
    digitalWrite(PIN_LED_RED, HIGH);
    tone(PIN_BUZZER, 400, 1000);

    // LCD
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("  ACCESS DENIED   ");
    lcd.setCursor(0, 1);
    lcd.print("UID: " + uid);
    lcd.setCursor(0, 2);
    lcd.print("Door: LOCKED");

    // Send log to dashboard
    sendLog(uid, "DENIED");
    delay(2000);
    resetDisplay();
}

void sendLog(String uid, String result) {
    StaticJsonDocument<256> doc;
    doc["uid"]    = uid;
    doc["result"] = result;
    doc["time"]   = millis();
    char buffer[256];
    size_t len = serializeJson(doc, buffer);
    webSocket.broadcastTXT(buffer, len);
}

void checkDoorTimeout() {
    if (doorIsOpen && (millis() - lastDoorOpen >= DOOR_OPEN_DURATION)) {
        doorServo.write(0);
        doorIsOpen = false;
        digitalWrite(PIN_LED_GREEN, LOW);
        resetDisplay();
    }
}

void resetDisplay() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("  FABLAB INPHB  ");
    lcd.setCursor(0, 1);
    lcd.print("Scan your badge...");
}

// ========================== SETUP ==========================
void setup() {
    Serial.begin(115200);

    // Pin setup
    pinMode(PIN_LED_GREEN, OUTPUT);
    pinMode(PIN_LED_RED,   OUTPUT);
    pinMode(PIN_BUZZER,    OUTPUT);

    // LCD init
    lcd.init();
    lcd.backlight();
    resetDisplay();

    // RFID init
    SPI.begin();
    rfid.PCD_Init();

    // Servo init
    doorServo.attach(PIN_SERVO);
    doorServo.write(0);  // Door locked by default

    // Wi-Fi
    WiFi.begin(SSID_WIFI, PASS_WIFI);
    lcd.setCursor(0, 3);
    lcd.print("Connecting WiFi...");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\n[WIFI] Connected! IP: " + WiFi.localIP().toString());
    lcd.setCursor(0, 3);
    lcd.print("IP: " + WiFi.localIP().toString());

    // WebSocket
    webSocket.begin();
    Serial.println("[WS] WebSocket started on port 81");
}

// ========================== LOOP ==========================
void loop() {
    webSocket.loop();
    checkDoorTimeout();

    // Check for new RFID badge
    if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;

    String uid = getUID(rfid);
    Serial.println("[RFID] Badge detected: " + uid);

    if (isAuthorized(uid)) {
        grantAccess(uid);
    } else {
        denyAccess(uid);
    }

    rfid.PICC_HaltA();
    rfid.PCD_StopCrypto1();
}

Step 4 — Software Integration (Web Dashboard)

The web management dashboard was built upon the skills acquired during Week 14 (Interface and Application Programming).

It communicates with the ESP32 via WebSocket on port 81, and allows the administrator to:

  • View the access log in real time (UID, result, timestamp)
  • Add or remove authorized badges
  • Receive visual alerts for unauthorized access attempts

Dashboard Interface


Step 5 — System Testing

Once all modules were assembled and the firmware uploaded, a series of tests were performed to validate the complete system:

Functional Tests

Test Description Result
Authorized badge scan Present a registered badge Door opens, green LED, short beep ✅
Unknown badge scan Present an unregistered badge Door stays locked, red LED, long beep ✅
Auto door close Wait 5 seconds after opening Door closes automatically ✅
LCD display Verify all messages display correctly Messages display properly ✅
WebSocket logging Check events appear in dashboard Events logged in real time ✅
Wi-Fi reconnection Disconnect/reconnect router System reconnects automatically ✅

Bill of Materials (BOM)

Component Reference Quantity Origin Price ($)
ESP32-WROOM-32D U1 1 Digikey $4.08
RFID Reader RC522 U2 1 Amazon $7.65
LCD 20x4 I2C LCD1 1 Amazon $10.00
Servo Motor SG90 M1 1 Amazon $3.00
Buzzer 5V BZ1 1 Digikey $0.61
LED Green SMD 1206 LED1 2 Digikey $0.78
LED Red SMD 1206 LED2 2 Digikey $0.78
Reg 3.3V SOT223 U3 1 Digikey $0.63
PCB FR4 (custom) PCB1 1 FabLab $3.00
3D Printed Enclosure (PLA) 1 FabLab $4.50
Jumper wires & connectors FabLab $2.00
TOTAL ~$37.03

Fabrication Processes Summary

Process Tool Used Week
PCB Design KiCad Week 6
PCB Milling Roland SRM-20 Week 8
3D Enclosure Design Fusion 360 Week 5
3D Printing Prusa i3 MK3S+ Week 5
Vinyl cutting (labels) Vinyl cutter Week 3
Embedded programming Arduino IDE Week 4
Network programming PlatformIO Week 11
Web interface HTML / JS / WebSocket Week 14

Result

After full integration, the system operates as expected:

  • Authorized badges are identified instantly and the door opens for 5 seconds before locking again.
  • All access events (authorized and denied) are logged in real time on the web dashboard.
  • The LCD provides clear, user-friendly feedback at all times.
  • The system reconnects to Wi-Fi automatically after a network interruption.