A complete offline IoT project using ESP32 + RFID RC522 + Flutter.
smart_door_lock/
├── esp32/
│ └── smart_door_lock.ino ← Upload this to ESP32
│
└── flutter_app/
├── pubspec.yaml
├── android/
│ └── app/src/main/
│ ├── AndroidManifest.xml
│ └── res/xml/network_security_config.xml
└── lib/
├── main.dart
├── models/
│ ├── log_entry.dart
│ └── rfid_card.dart
├── screens/
│ ├── home_screen.dart
│ ├── logs_screen.dart
│ ├── manage_cards_screen.dart
│ └── settings_screen.dart
└── services/
├── api_service.dart
└── preferences_service.dart
RC522 Pin → ESP32 Pin
─────────────────────────
VCC (3.3V) → 3.3V
GND → GND
SDA (SS) → GPIO 5
SCK → GPIO 18
MOSI → GPIO 23
MISO → GPIO 19
RST → GPIO 4
IRQ → (not connected)
Servo Wire → ESP32 Pin
───────────────────────────
Signal (orange) → GPIO 13
VCC (red) → 5V (VUSB or external)
GND (brown) → GND
⚠️ Important: Do NOT power the servo from ESP32's 3.3V. Use the 5V (VUSB) pin or an external 5V supply. High servo current can reset the ESP32 if underpowered.
LCD I2C Pin → ESP32 Pin
──────────────────────────
VCC → 5V
GND → GND
SDA → GPIO 21
SCL → GPIO 22
The I2C address is typically 0x27. If LCD doesn't work, try 0x3F. Edit
LCD_ADDRin the .ino file.
LED Color → ESP32 Pin (with 220Ω resistor in series)
────────────────────────────────────────────────────────────
Green LED → GPIO 25 → 220Ω → GND
Red LED → GPIO 26 → 220Ω → GND
┌──────────────┐
│ │
RC522 SDA ───┤ GPIO 5 │
RC522 SCK ───┤ GPIO 18 │
RC522 MOSI ───┤ GPIO 23 │
RC522 MISO ───┤ GPIO 19 │
RC522 RST ───┤ GPIO 4 │
│ │
Servo Signal ──┤ GPIO 13 │
│ │
LCD SDA ───┤ GPIO 21 │
LCD SCL ───┤ GPIO 22 │
│ │
Green LED ───┤ GPIO 25 │
Red LED ───┤ GPIO 26 │
│ │
GND ───┤ GND │
5V ───┤ 5V / VUSB │
3.3V ───┤ 3V3 │
└──────────────┘
ESP32
Install these in Arduino IDE (Sketch → Include Library → Manage Libraries):
| Library | Install Name | Notes |
|---|---|---|
| MFRC522 | MFRC522 |
by GithubCommunity |
| ESP32Servo | ESP32Servo |
NOT the regular Servo lib |
| LiquidCrystal I2C | LiquidCrystal I2C |
by Frank de Brabander |
| ArduinoJson | ArduinoJson |
v6.x or v7.x |
| WebServer | Built-in with ESP32 board package |
- Open Arduino IDE
- Go to File → Preferences
- Add to "Additional boards manager URLs":
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - Go to Tools → Board → Boards Manager
- Search "esp32" → Install "esp32 by Espressif Systems"
- Select Tools → Board → ESP32 Arduino → ESP32 Dev Module
- Flutter SDK installed (flutter.dev)
- Android Studio or VS Code with Flutter extension
- A physical Android or iOS device (for WiFi connectivity)
cd flutter_app
flutter pub get
flutter runNote: Must run on a real device, not emulator. The emulator cannot connect to local WiFi networks where ESP32 lives.
- Power on the ESP32
- On your phone → Settings → WiFi
- Connect to: SmartLock_AP
- Password: smartlock123
- Open the app → Settings → IP:
192.168.4.1 - Tap "Save & Test"
- In
smart_door_lock.ino, set:#define USE_AP_MODE false const char* STA_SSID = "YourRouterName"; const char* STA_PASSWORD = "YourRouterPassword";
- Upload to ESP32
- Check your router's admin panel for the ESP32's assigned IP
- Enter that IP in the Flutter app Settings
Base URL: http://192.168.4.1 (or your custom IP)
Returns API info page (HTML).
Manually check if a UID is authorized.
Request Body:
{
"uid": "AABBCCDD"
}Response (Granted):
{
"status": "granted",
"uid": "AABBCCDD",
"timestamp": "T+00:05:23"
}Response (Denied):
{
"status": "denied",
"uid": "DEADBEEF",
"timestamp": "T+00:06:01"
}Returns all access logs (newest first, max 100).
Response:
[
{
"uid": "AABBCCDD",
"timestamp": "T+00:05:23",
"status": "granted"
},
{
"uid": "DEADBEEF",
"timestamp": "T+00:04:10",
"status": "denied"
}
]Register a new RFID card.
Request Body:
{
"uid": "11223344",
"label": "Guest Key"
}Response (Success):
{
"success": true,
"message": "Card added"
}Response (Already exists — 409):
{
"success": false,
"message": "Card already registered"
}Returns all registered RFID cards.
Response:
[
{
"uid": "AABBCCDD",
"label": "Master Key"
},
{
"uid": "11223344",
"label": "Spare Key"
}
]Remove a registered card.
Response (Success):
{
"success": true,
"message": "Card removed"
}Response (Not found — 404):
{
"success": false,
"message": "Card not found"
}- Open the Flutter app → Connect to ESP32
- Scan the RFID card on the reader
- The ESP32 will deny it (since it's not registered yet)
- Go to View Logs in the app
- You'll see the new UID in the denied entry
- Copy that UID
- Go to Manage Cards → Add Card
- Paste the UID and give it a label
| Problem | Solution |
|---|---|
| LCD shows nothing | Check I2C address — try 0x3F instead of 0x27 |
| RFID not detecting | Verify SPI wiring; use 3.3V not 5V for RC522 |
| Servo not moving | Power servo from 5V, not 3.3V |
| App can't connect | Ensure phone is on SmartLock_AP WiFi, not mobile data |
| HTTP blocked on Android | Verify network_security_config.xml is in place |
| Serial shows garbage | Set baud rate to 115200 in Serial Monitor |
| Cards lost on reboot | Normal — cards are in memory. Add persistence with EEPROM/Preferences if needed |
- Wire all components per diagram above
- Install Arduino libraries
- Set WiFi mode in .ino (AP mode is default — no changes needed)
- Upload .ino to ESP32
- Open Serial Monitor (115200 baud) — verify "System Ready"
- Run
flutter pub getin flutter_app/ - Run app on real device (not emulator)
- Connect phone to "SmartLock_AP" WiFi
- Open app → Settings → Verify IP is 192.168.4.1 → Save & Test
- Scan a card → Check logs → Add it via Manage Cards
- Scan registered card → Servo unlocks ✓
-
Data persistence: Card list and logs are stored in RAM only. They will be lost on ESP32 reboot. For permanent storage, use
Preferences.h(ESP32 NVS) or an SD card module. -
Multiple cards: Up to 50 cards supported (MAX_CARDS constant).
-
Auto-lock: Door locks automatically after 3 seconds (LOCK_DELAY_MS).
-
Timestamps: Format is
T+HH:MM:SS(time since boot). To use real clock time, add an RTC module (DS3231) or use NTP if connected to internet. "# smart_door_lock"