Skip to content

Final Project Development

Inspiration

Input and the Output considered

Input

  • RFID card and RFID scanner

Output

  • Solenoid

  • Neopixels

  • Sound

Prototyping

Initial rapid prototyping

I made my cardboard prototype using cardboard.I used the dxf file formate from the fusion and I used the Zund to cut the cardboard.The picture below is my first prototype.

Why initial prototyping?

This will allows me to figure out:
- What to Change: You can see what works and what doesn’t, so you know how to make your idea better.
- How Big to Make It: You can decide how big or small your project should be.
- Where to Put Things: You get to plan where each piece should go, like putting together a puzzle.
- What It Will Look Like: You get a sneak peek of how your final project might turn out, so you can focus on fixing or improving the parts that need work.

2nd Prototyping

I want to design cabinet with drawers that blinks the neopixels in calming pattern. When an authorized user touches the drawer door, the system detects the interaction, the decorative LEDs gently blink in a calming pattern (e.g., slow fade-in and fade-out) to indicate the system is active and ready.

I found this idea from the pinterest. I was thining of making this drawers door in modling casting week.

Here is my second version of the prototype drawer

Materials

Component Price Link
Seeeduino XIAO ESP32 C3 Microcontroller $12.99 Amazon Link
RC522 RFID Module $15.99 (pack of 5 modules) Amazon Link
Neopixel ~$1 each N/A
Miscellaneous Components (Jumper wires, resistors, etc.) $6.98 (120-piece kit) Amazon Link
Solenoid Lock $10–$20 Amazon Link
Relay Module $5–$10 Amazon Link
Rubber wood $51.76 USD Amazon Link
3D printed PCB casing $1.73 USD Amazon Link
                  |

Total Estimated Cost:

  • $12.99 (microcontroller)
  • $15.99 (RFID modules)
  • $1 (neopixels)
  • $6.98 (miscellaneous components)
  • $10–$20 (solenoid lock)
  • $5–$10 (relay module)

Total: $120.45 USD

Therefore, the total estimated cost ranges 9,997.35 BTN.

Week 02

In week two I tired making my first cabinet. I used the fusion 360 to do my designing. This is how my cabinet going to look.

Week04

In embeded programming week, I tired to programming using Esp32 as mcu and lcd with leds.

How it Works?
Inital Electronics design

I used the code by from here

📌

       #include <LiquidCrystal.h>
       // Define ESP32 GPIO pins for parallel LCD
       LiquidCrystal lcd(14, 12, 27, 26, 25, 33);  // LCD pins
       // ✅ Define LED GPIOs BEFORE setup()
        #define LED1 19
         #define LED2 5
         #define LED3 17
          #define BACKLIGHT 21
          void setup() {
         // Set LCD backlight pin as output
     pinMode(BACKLIGHT, OUTPUT);
      digitalWrite(BACKLIGHT, HIGH); // Turn ON backlight
      // Set LED pins as outputs and initialize them OFF
     pinMode(LED1, OUTPUT);
      pinMode(LED2, OUTPUT);
      pinMode(LED3, OUTPUT);
      digitalWrite(LED1, LOW);
     digitalWrite(LED2, LOW);
     digitalWrite(LED3, LOW);
     // Initialize the LCD
     lcd.begin(16, 2); // Assuming a 16x2 LCD
     }
     void loop() {
        // Blink LED1 and display message

    digitalWrite(LED1, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Authorized ");
    delay(1000); 
    digitalWrite(LED1, LOW);
    lcd.clear();
    // Blink LED2 and display message
    digitalWrite(LED2, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Not auhorized");
    delay(1000);
    digitalWrite(LED2, LOW);
    lcd.clear();
    // Blink LED3 and display message
    digitalWrite(LED3, HIGH);
    lcd.setCursor(0, 0);
     lcd.print("Scan Again");
     delay(1000);
     digitalWrite(LED3, LOW);
      lcd.clear();
      delay(1000); // Pause before loop repeats
      }

Week 06

In week 06 I tired designing my board, I used the esp32 as MCU.Given below is the rough skecth of how my wiring will be

My first schematic

My first PCB

Week08.

In electronics production week, I tired redesign my board using XIAO RP2040. I milled and soldered my board.

My new schematic circuit design

My pcb

Week 09

In the input week, I tired using the RFID as the input to read the card UID

    #include <SPI.h>
    #include <MFRC522.h>

   #define SS_PIN D2  // Chip Select pin
   #define RST_PIN D1 // Reset pin

    MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance

    void setup() {
    Serial.begin(9600); // Initialize serial communication
     SPI.begin();        // Initialize SPI bus
     mfrc522.PCD_Init(); // Initialize MFRC522
     Serial.println("RFID Scanner Ready!");
    }

    void loop() {
    // Look for new cards
      if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
     Serial.println("Card detected!");

     // Print UID of the card
     Serial.print("UID: ");
     for (byte i = 0; i < mfrc522.uid.size; i++) {
     Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
      Serial.print(mfrc522.uid.uidByte[i], HEX);
     }
     Serial.println();

    mfrc522.PICC_HaltA(); // Halt PICC
     }
     }

Here is rough sketch of my wiring, I am thinking of using the ESP32C3 as the for my final project. Before designing in the Kicad, I want to first try the circuit in the output week and check what are the changes to be done. after that I will make design the circuit for the PCB.

Week10

This week I used neopixels and solenoid to as output, as this I will be using the solenoid and neopixels for my final project.

Solenoid

I uploaded the code in arduino IDE, The code I used:

📌

  const int relayPin = 13; // GPIO pin connected to the relay module

  void setup() {
  pinMode(relayPin, OUTPUT);
  }

  void loop() {
  // Switch on the solenoid
  digitalWrite(relayPin, HIGH); 
  delay(1000); // Solenoid remains ON for 1 second

 // Switch off the solenoid
 digitalWrite(relayPin, LOW);
   delay(5000); // Solenoid remains OFF for 5 seconds

}

Neopixels

  #include <SPI.h>
  #include <MFRC522.h>
  #include <Adafruit_NeoPixel.h>

  #define RFID_SS_PIN 10
  #define RFID_RST_PIN 9
  #define NEOPIXEL_PIN 6
  #define NUMPIXELS 8  // Number of NeoPixels

  MFRC522 mfrc522(RFID_SS_PIN, RFID_RST_PIN);
 Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);

 // Replace with your authorized card UIDs
 byte authorizedUID1[] = {0xDE, 0xAD, 0xBE, 0xEF}; // Example UID - replace with yours
 byte authorizedUID2[] = {0x12, 0x34, 0x56, 0x78}; // Add more as needed

 void setup() {
 Serial.begin(9600);
 SPI.begin();
 mfrc522.PCD_Init();
 pixels.begin();
 pixels.setBrightness(50); // Adjust brightness (0-255)
 Serial.println("RFID + NeoPixel Ready");
 }

 void loop() {
 // Reset the loop if no new card present
 if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
  delay(50);
  return;
 }

 Serial.print("Card UID:");
 for (byte i = 0; i < mfrc522.uid.size; i++) {
  Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
  Serial.print(mfrc522.uid.uidByte[i], HEX);
 }
 Serial.println();

  // Check if card is authorized
 bool isAuthorized = false;
 if (compareUID(mfrc522.uid.uidByte, authorizedUID1, 4) || 
  compareUID(mfrc522.uid.uidByte, authorizedUID2, 4)) {
  isAuthorized = true;
 }

  // Light up NeoPixels based on authorization
  if (isAuthorized) {
  authorizedAnimation();
  Serial.println("Authorized - Rainbow colors!");
 } else {
  unauthorizedRed();
  Serial.println("Unauthorized - Red alert!");
 }

  delay(1000); // Debounce delay
  mfrc522.PICC_HaltA();
 }

 bool compareUID(byte *a, byte *b, byte len) {
 for (byte i = 0; i < len; i++) {
 if (a[i] != b[i]) return false;
 }
 return true;
 }

 void authorizedAnimation() {
  // Green, Yellow, Blue, Indigo, Violet sequence
  uint32_t colors[] = {
  pixels.Color(0, 255, 0),    // Green
  pixels.Color(255, 255, 0),  // Yellow
 pixels.Color(0, 0, 255),    // Blue
 pixels.Color(75, 0, 130),   // Indigo
 pixels.Color(148, 0, 211)   // Violet
 };

 for (int color = 0; color < 5; color++) {
 for (int i = 0; i < NUMPIXELS; i++) {
  pixels.setPixelColor(i, colors[color]);
  }
  pixels.show();
  delay(300); // Time between color changes
 }
 }

  void unauthorizedRed() {
  for (int i = 0; i < NUMPIXELS; i++) {
  pixels.setPixelColor(i, pixels.Color(255, 0, 0)); // Red
  }
  pixels.show();
  delay(1000); // Red stays on for 1 second
 }

Final Code 1

  #include <SPI.h>
 #include <MFRC522.h>
 #include <Adafruit_NeoPixel.h>
 #define BLYNK_PRINT Serial

 #include <DFRobotDFPlayerMini.h>
 #include <SoftwareSerial.h>

 // Initialize software serial on pins D3 (RX) and D4 (TX)
 SoftwareSerial mySerial(D4, D3);

  // Create DFPlayer object
  DFRobotDFPlayerMini myDFPlayer;


 // Blynk credentials
 #define BLYNK_TEMPLATE_ID "TMPL390VtiLXt"
 #define BLYNK_TEMPLATE_NAME "Relay IOT"
 #define BLYNK_AUTH_TOKEN "AXrEK2JeuEziwFHw4ZFahgrJJkdrlXSE"

 #include <WiFi.h>
 #include <WiFiClient.h>
 #include <BlynkSimpleEsp32.h>

 // WiFi credentials
 char ssid[] = "Fablab";
 char pass[] = "#JSW@2o25";

 #define PIN D2          // Pin where NeoPixel is connected
  #define NUMPIXELS 30    // Change this to match your strip length

 Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

  constexpr uint8_t RST_PIN = D0;     
 constexpr uint8_t SS_PIN = D7;     
  const int relayPin = D1;

  MFRC522 rfid(SS_PIN, RST_PIN); 
 MFRC522::MIFARE_Key key;

 byte nuidPICC[4];

   // Authorized card UIDs
 byte authorizedUID1[4] = {0xCC, 0x82, 0x36, 0x4A};
  byte authorizedUID2[4] = {0xFC, 0x4D, 0x11, 0x4A};

  bool flag = true;
  bool blynkTriggered = false;

 //---------------------------- neo pixel variables
  unsigned long lastActionTime = 0;
 unsigned long rainbowInterval = 5000; // 5 seconds
 bool overrideColor = false;
 //-------------------------------------------------

 int value;

  BLYNK_WRITE(V0) {
  value = param.asInt(); // Get value from Blynk app

  if(value == 1){
  Serial.println("Opening door...");
  myDFPlayer.play(1);  // Play track 0001.mp3
 showRhombusPattern(pixels.Color(0, 255, 0)); // Green for authorized
  delay(500);
  digitalWrite(relayPin, value);
  }

  else {
  Serial.println("Closing door...");
 myDFPlayer.play(2);  // Play track 0001.mp3
  digitalWrite(relayPin, value);
  }
 delay(5000);
 }

 void setup() { 
 Serial.begin(115200);
 mySerial.begin(9600);  // Start software serial for DFPlayer
  Serial.println(F("Initializing DFPlayer..."));
 // Initialize DFPlayer
  if (!myDFPlayer.begin(mySerial)) {
  Serial.println(F("DFPlayer initialization failed!"));
  Serial.println(F("1. Check RX/TX connections (must be crossed)"));
  Serial.println(F("2. Insert SD card with MP3 files"));
  while(true);  // Halt if initialization fails
  }

  Serial.println(F("DFPlayer Mini ready!"));
  myDFPlayer.volume(30);  // Set volume (0-30)

  // while (!Serial);
  Serial.flush();
  delay(1000);
  Serial.println("Starting RC522...");

  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, LOW); // Ensure relay is off initially

  SPI.begin(); 
  rfid.PCD_Init();

  for (byte i = 0; i < 6; i++) {
  key.keyByte[i] = 0xFF;
 }

  Serial.println(F("Ready to scan cards Bir, Here! ..."));

  pixels.begin();
  pixels.show(); // Turn off all pixels

 // Connect to Blynk
 Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);

 }

  void loop() {

  Blynk.run();

   if (millis() - lastActionTime > rainbowInterval && !overrideColor) {
  //showRainbowPattern();
  showRhombusPattern(pixels.Color(255, 255, 255)); // white for ideal state
  lastActionTime = millis();
  }

   // Reset override after showing status for a short while
   if (overrideColor && millis() - lastActionTime > 3000) {
    overrideColor = false;
    lastActionTime = millis();
   }
   if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;

  Serial.println(F("Card detected. UID:"));
 printHex(rfid.uid.uidByte, rfid.uid.size);
 Serial.println();

  if (isAuthorized(rfid.uid.uidByte)) {
  Serial.println("Authorized card detected!");
  overrideColor = true;

   if (flag) {
  Serial.println("Opening door...");
  myDFPlayer.play(1);  // Play track 0001.mp3
  //delay(5000);         // Wait 5 seconds

  // showColor(pixels.Color(0, 255, 0));
  showRhombusPattern(pixels.Color(0, 255, 0)); // Green for authorized
  delay(500);
  digitalWrite(relayPin, HIGH);
} else {
  Serial.println("Closing door...");
  myDFPlayer.play(2);  // Play track 0002.mp3
  //delay(5000);         // Wait 5 seconds

  digitalWrite(relayPin, LOW);
  }

  lastActionTime = millis();

  flag = !flag;
  delay(5000); // Keep the relay active for 5 seconds
   } else {
   Serial.println("Unauthorized card.");
   myDFPlayer.play(3);  // Play track 0001.mp3
   //delay(5000);         // Wait 5 seconds
   // showColor(pixels.Color(255, 0, 0));
   showRhombusPattern(pixels.Color(255, 0, 0)); // Red for unauthorized
   }

  // Reset RFID reader
  rfid.PICC_HaltA();
 rfid.PCD_StopCrypto1();
  rfid.PCD_Init();
 delay(100);
 }


  // Show rhombus pattern (assuming 4 LEDs in a square configuration)
 void showRhombusPattern(uint32_t color) {
  // Sequence for rhombus pattern: 0, 1, 3, 2 (assuming physical layout)
  int rhombusSequence[30] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29};

  // First turn all LEDs off
 pixels.clear();

  // Light up LEDs in rhombus pattern
  for (int i = 0; i < NUMPIXELS; i++) {
  pixels.setPixelColor(rhombusSequence[i], color);
  pixels.show();
 delay(100); // Small delay for visible sequence
  }

 // Keep all rhombus LEDs on for a moment
 delay(500);
 }

 bool isAuthorized(byte *uid) {
  return compareUID(uid, authorizedUID1) || compareUID(uid, authorizedUID2);
 }

 bool compareUID(byte *uid, byte *authorizedUID) {
 for (byte i = 0; i < 4; i++) {
 if (uid[i] != authorizedUID[i]) return false;
 }
 return true;
 }

 void printHex(byte *buffer, byte bufferSize) {
 for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
 }
 }


void showColor(uint32_t color) {
 for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, color);
 }
 pixels.show();
 }

 void showRainbowPattern() {
 for (int j = 0; j < 256; j++) {
 for (int i = 0; i < NUMPIXELS; i++) {
  pixels.setPixelColor(i, Wheel((i * 256 / NUMPIXELS + j) & 255));
  }
  pixels.show();
  delay(10); // Small delay for visible rainbow motion
 }
 }

 uint32_t Wheel(byte WheelPos) {
 WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
   return pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
 if (WheelPos < 170) {
  WheelPos -= 85;
  return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
 }
 WheelPos -= 170;
  return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
 }