A DIY digital camera with a physical shutter, SD card storage and a Wi-Fi web gallery — built on the AI-Thinker ESP32-CAM with the OV3660 sensor.
OV3660 · 3 MP · SD card · Wi-Fi gallery · Arduino IDE · ~200 Kč total cost
00 — Bill of materials
| Qty | Part | Note |
|---|---|---|
| 1× | AI-Thinker ESP32-CAM + OV3660 + baseboard | your module |
| 1× | MicroSD card (Class 10, FAT32 formatted) | 8–32 GB recommended |
| 1× | Momentary push button (6 mm tactile switch) | shutter button |
| 1× | Li-Po battery 3.7 V, 1000–2000 mAh | or a USB power bank |
| 1× | TP4056 Li-Po charger module (with protection) | for battery charging |
| 1× | MT3608 boost converter (5 V output) | if using the Li-Po directly |
| 1× | SPDT slide switch | power on/off |
| — | Jumper wires, heat-shrink, small proto board |
01 — Hardware wiring
The AI-Thinker baseboard already includes the USB-to-serial chip for programming. For the camera build, you only need to wire the shutter button and the power circuit.
Important: the ESP32-CAM uses GPIO pins for the SD card in 1-bit MMC mode. GPIO13 is free in this mode and is used for the shutter button. Do NOT connect anything else to GPIO4 (flash LED) or the SD card pins while the camera is running.
Shutter button
| ESP32-CAM pin | Component | Notes |
|---|---|---|
| GPIO13 | Button pin 1 | INPUT_PULLUP — button pulls to GND |
| GND | Button pin 2 | Active LOW — no resistor needed |
Power circuit
| Module | From | To | Notes |
|---|---|---|---|
| Slide switch | Li-Po + | TP4056 BAT+ | Main power switch |
| TP4056 | BAT+ / BAT− | MT3608 IN+ / IN− | Charge protection |
| MT3608 | OUT+ | Baseboard 5 V | Boost to 5 V, adjust the trimmer |
| GND common | All GNDs | Baseboard GND | Star topology preferred |
Simplest power option: if you want to skip the battery circuit for now, power the baseboard via its micro-USB port from a small USB power bank. This lets you test everything immediately.
SD card
The microSD card slot is built into the ESP32-CAM module. Format your card as FAT32 and insert it
before powering on. The firmware automatically creates a /photos folder.
02 — Firmware setup
Arduino IDE configuration
-
Install Arduino IDE 2.x from arduino.cc.
-
Add the ESP32 board package URL in File → Preferences → Additional Boards Manager URLs:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json -
Go to Tools → Board → Boards Manager, search for esp32 by Espressif and install version 2.x.
-
Select the board: AI Thinker ESP32-CAM.
-
Set the partition scheme: Huge APP (3MB No OTA/1MB SPIFFS).
-
Set PSRAM: Enabled.
Edit the firmware
Open esp32cam_camera.ino and update lines 17–18 with your Wi-Fi credentials:
const char* WIFI_SSID = "YourNetworkName";
const char* WIFI_PASSWORD = "YourPassword";
Upload / flashing
Before uploading: the baseboard has an IO0 button for programming mode. Hold IO0 while pressing RESET (or power-cycling) to enter bootloader mode, then click Upload in the Arduino IDE.
- Connect the baseboard to your computer via USB (it uses the onboard CH340/CP2102 chip).
- Select the correct COM/serial port in the Arduino IDE.
- Hold the IO0 button on the baseboard.
- Press RESET once (still holding IO0).
- Release IO0, then click Upload ↑ in the Arduino IDE.
- After the upload completes, press RESET again to run.
Verify it works
- Open the Serial Monitor at 115200 baud.
- You should see: camera init OK → SD card OK → Wi-Fi IP address.
- Open a browser and navigate to the IP address shown.
- The web gallery UI should load immediately.
03 — Web gallery
The web interface is served directly from the ESP32. Connect any device on your local network to:
http://<ESP32-IP-address>/
Available endpoints:
| URL | Method | Description |
|---|---|---|
/ |
GET | Web gallery UI |
/capture |
GET | Trigger a photo, returns JSON |
/list |
GET | JSON array of all photo filenames |
/photo?name=IMG_1.jpg |
GET | View a photo inline |
/photo?name=IMG_1.jpg&dl=1 |
GET | Download a photo |
04 — OV3660 tuning
The OV3660 is a 3 MP sensor (better than the common OV2640). These settings in the firmware can be adjusted:
sensor_t* s = esp_camera_sensor_get();
s->set_vflip(s, 1); // 1 = flip vertically (OV3660 default mount)
s->set_hmirror(s, 0); // 1 = mirror horizontally
s->set_brightness(s, 1); // -2 to +2
s->set_saturation(s, 0); // -2 to +2
s->set_contrast(s, 0); // -2 to +2
s->set_whitebal(s, 1); // auto white balance
s->set_awb_gain(s, 1); // AWB gain
s->set_aec2(s, 1); // auto exposure advanced
s->set_ae_level(s, 0); // -2 to +2 exposure bias
Resolution options
| Constant | Resolution | Use case |
|---|---|---|
FRAMESIZE_UXGA |
1600×1200 | Best quality (default) |
FRAMESIZE_SXGA |
1280×1024 | Good balance |
FRAMESIZE_XGA |
1024×768 | Faster capture |
FRAMESIZE_VGA |
640×480 | Fastest, small files |
05 — Enclosure ideas
A few approaches for housing the build:
Option A — 3D-printed body
Search Printables or Thingiverse for “ESP32-CAM case”. Many designs exist for the AI-Thinker module. Add a custom top panel with a hole for the OV3660 lens, a slot for the SD card and a recessed shutter button.
Option B — Altoids tin / project box
A 100 × 60 mm ABS project box from TME/GM Electronic fits the module and a small Li-Po. Drill a lens hole (the OV3660 needs a ~10 mm cutout) and mount the button on top.
Option C — Compact USB power bank
Some ultra-slim power banks (Xiaomi Slim 5000) are barely larger than the ESP32-CAM itself. Tape the module to the back, run a short USB cable and you have instant power without any soldering.
Key dimensions: AI-Thinker ESP32-CAM PCB: 40 × 27 mm. The OV3660 camera module protrudes ~15 mm above the PCB. The baseboard adds ~5 mm to the bottom.
06 — Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Camera init failed 0x105 | Camera not detected | Check the ribbon cable is seated and power is adequate (≥ 500 mA) |
| SD card mount failed | Wrong format or bad card | Reformat as FAT32, try another card |
| Image upside-down | OV3660 mounting | Toggle set_vflip(s, 0) or 1 |
| Wi-Fi not connecting | Wrong credentials or range | Check SSID/password, move closer to the router |
| Brownout reset on capture | Insufficient current | Use a quality USB cable and a ≥ 1 A supply |
| Photo saved but 0 bytes | Frame buffer error | Add delay(500) before the first capture in setup() |
| Button fires multiple times | Bounce | Increase DEBOUNCE_MS to 500 |
The complete Arduino sketch, esp32cam_camera.ino, sits next to the original guide in my portfolio
repository (blog-posts/pointandshoot-cam/esp32cam_camera.ino).