Built in collaboration with Claude
A Wi-Fi enabled point-and-shoot camera built for the AI-Thinker ESP32-CAM.
Charm-Cam turns the ESP32-CAM into a small standalone camera with a built-in web UI, SD card storage, analog film-roll simulation, digital mode, physical shutter support, and OTA firmware updates — designed to feel like a keychain charm you carry around and snap with.
- Access Point mode with configurable SSID and password
- Web UI for shooting, gallery viewing, archive browsing, and settings
- Two camera modes:
- Analog mode: load a film, shoot up to 36 frames, then develop the roll
- Digital mode: unlimited direct-to-gallery captures
- Physical shutter button support on GPIO13
- SD card image storage
- Developed roll archive storage by roll folder, with auto-incrementing roll numbers preserved across reboots
- Rename developed rolls from the web UI
- Delete individual saved photos and entire developed rolls from the web UI
- Toggleable flash for captures
- EXIF orientation tag injected at save time (zero-cost rotation, no re-encode)
- Persistent settings and roll state using ESP32 Preferences
- OTA firmware update page
- LED feedback for status, warnings, roll full, and new roll loaded
Frames captured with Charm-Cam, straight from the SD card with no post-processing.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
The whole interface runs on the ESP32-CAM itself — no cloud, no companion app, no internet required. Connect to the camera's Wi-Fi hotspot, open http://192.168.4.1 in any browser (phone, tablet, laptop), and you get a self-contained film-camera UI styled in amber-on-black.
3D-printed in orange and black, just barely bigger than a thumbnail, with the same form-factor DNA as the analog point-and-shoot cameras that inspired it — built to live on a keychain.
![]() |
![]() |
Total cost: roughly $20 USD for all electronic parts shipped from AliExpress (excluding the printed enclosure, which is a few grams of filament).
Designed for:
- AI-Thinker ESP32-CAM with OV2640 camera module — buy on AliExpress

- Battery — 3.7 V Li-Po cell, optimal dimensions 39 × 26 × 4.5 mm to fit the enclosure. The prototype uses a 502040 350 mAh cell (40 × 20 × 5 mm) — buy on AliExpress

- USB C Charging board — buy on AliExpress

- Flat on/off switch — ESP1010 side-actuated slide switch — buy on AliExpress

- Momentary shutter button — 6 × 6 × 6 mm SMD tact switch, connected between GPIO13 and GND — buy on AliExpress

- microSD card
All case files live in 3D Files/ — ready-to-print meshes plus the editable CAD source so you can modify the design:
Charm-Cam-Front-v1.stl/Charm-Cam-Back-v1.stl— main body halvesCharm-Cam-Cage-v1.stl— internal frame holding the ESP32-CAM and batteryCharm-Cam-ESP-Cover-v1.stl— module coverCharm-Cam-Lens-v1.stl— lens bezelCharm-Cam-Parts-Holder-v1.stl— print-bed jig for small partsCharm-Cam-v1-PrintFILE.3mf— pre-arranged print plate (PrusaSlicer / Bambu Studio)Charm-Cam-Fusion360.f3d— editable Fusion 360 source, open this to tweak dimensions, change cut-outs, or remix the design
![]() |
![]() |
- USB-C charging board → ESP32-CAM
5V/GND(power in, with the slide switch breaking the 5V line) - Li-Po battery → charging board
B+/B- - ESP1010 slide switch → in-line on the 5V rail between charging board and ESP32-CAM (cuts power when off)
- 6×6×6 tact button → ESP32-CAM
GPIO13↔GND(the firmware usesINPUT_PULLUP, no external resistor needed) - Onboard flash LED (GPIO4) and status LED (GPIO33) are already on the ESP32-CAM board
- GPIO13: shutter button
- GPIO4: flash LED
- GPIO33: red status LED (active LOW)
- Load a film roll from the web UI
- Capture up to 36 photos
- When the roll is full, the flash LED blinks quickly 3 times
- Develop the roll from the UI or by a long press of the shutter button
- Developed rolls are stored in archive folders on the SD card
- No film loading required
- No 36-frame limit
- Captured images are saved directly to the gallery
- Short press: capture immediately
- Long press (2 seconds) in analog mode: develop the current roll and automatically load a new roll of the same film
- If no film is loaded in analog mode, the status LED blinks 3 times as a warning
Images are saved on the microSD card.
Typical folder structure:
/roll/- current undeveloped analog roll/photos/- developed rolls and digital captures/photos/rNN_filmname/- one developed analog roll archive folder (NN is an auto-incrementing roll counter persisted in NVS)
After boot, the ESP32-CAM creates its own Wi-Fi hotspot.
Default settings:
- SSID:
Charm-Cam - Password:
camera123
Connect to the hotspot and open the device IP shown in Serial Monitor, typically:
http://192.168.4.1
From the web UI you can:
- capture photos
- load film
- develop rolls
- browse gallery and roll archive
- rename developed rolls
- delete saved photos or whole developed rolls
- switch between analog and digital mode
- toggle the flash on or off
- change hotspot name and password
- open the OTA firmware update page
End-to-end instructions to go from zero to a working Charm-Cam.
- All parts from the Hardware list — ~$20 USD total from AliExpress
- A 3D printer (or a print service) for the enclosure
- A computer with a USB port
- A USB cable suitable for your flashing setup (see step 5)
- Basic soldering iron + thin wire (28–30 AWG works well)
- Roughly 2–3 hours of build time (excluding the print)
Open 3D Files/Charm-Cam-v1-PrintFILE.3mf in PrusaSlicer or Bambu Studio — the plate is already arranged. If you prefer to arrange manually, use the individual .stl files in 3D Files/.
Recommended print settings:
- Material: PLA or PETG
- Layer height: 0.16 mm (or 0.2 mm if you're in a hurry)
- Walls: 3 perimeters
- Infill: 20 % grid or gyroid
- Supports: only where the slicer suggests them — the parts are designed to print mostly support-free
- Print time: ~3–5 hours depending on slicer/printer
Once printed, dry-fit the ESP32-CAM into the cage and check the lens bezel slides onto the camera module before soldering anything.
Download Arduino IDE 2.x from arduino.cc/en/software and install it. Launch it once to let it create its Arduino folder in your Documents.
- Open File → Preferences.
- In Additional boards manager URLs, paste:
(Multiple URLs go on separate lines.)
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - Tools → Board → Boards Manager… → search
esp32→ install "esp32" by Espressif Systems (latest stable, 2.x or newer).
Either:
- Click Code → Download ZIP on this GitHub page and unzip it, or
- Clone with git:
git clone https://github.com/FRSname/charm-cam.git
In Arduino IDE: File → Open… and pick esp32cam_camera-v1.2/esp32cam_camera-v1.2.ino. The other .ino, .h, and config.h files in the same folder will open as tabs alongside it.
In the Tools menu, set:
- Board → ESP32 Arduino → AI Thinker ESP32-CAM
- Partition Scheme → Minimal SPIFFS (1.9MB APP with OTA / 190KB SPIFFS)
(Required for OTA — the default partition has no OTA slot.) - CPU Frequency → 240MHz
- Flash Mode → QIO
- Flash Frequency → 80MHz
- Upload Speed → 115200 (raise later if reliable)
The bare AI-Thinker ESP32-CAM has no USB — you need one of:
- ESP32-CAM-MB baseboard (recommended) — plugs onto the ESP32-CAM pins, exposes a USB-C/micro-USB port, and handles the auto-reset-into-flashing-mode dance for you. No jumpers needed.
- USB-to-TTL adapter (CP2102, CH340, FT232) — wire it manually:
- Adapter
5V→ ESP32-CAM5V - Adapter
GND→ ESP32-CAMGNDand ESP32-CAMGPIO0(jumper GPIO0 to GND to enter flash mode) - Adapter
TX→ ESP32-CAMU0R - Adapter
RX→ ESP32-CAMU0T - Press the on-board RST button just before upload starts. Remove the GPIO0 jumper after flashing.
- Adapter
Plug it into your computer and confirm the COM port appears in Tools → Port.
- Select the COM port assigned to your adapter / baseboard.
- Click Upload (the right arrow icon).
- Wait through compile + upload. The first build takes a couple of minutes; subsequent ones are faster.
- Open Tools → Serial Monitor at 115200 baud. You should see:
Charm-Cam starting... >> STEP 1: WiFi AP... Hotspot: Charm-Cam — connect and go to http://192.168.4.1
Test the firmware before you solder anything into the case — easier to fix issues now.
- On your phone or laptop, connect to the Wi-Fi network
Charm-Cam(passwordcamera123). - Open http://192.168.4.1 in a browser.
- Load a film, take a shot. Confirm it appears in the gallery.
- If anything is broken, fix it before assembly. Re-flash as needed.
With the ESP32-CAM out of the baseboard, follow the diagram in Wiring. In order:
- Solder the 6×6×6 tact button between ESP32-CAM
GPIO13andGND. Keep wires short and route them along the cage. - Solder a wire from the USB-C charging board OUT+ to one terminal of the ESP1010 slide switch, then from the other switch terminal to ESP32-CAM 5V. The switch breaks the 5V rail.
- Solder USB-C charging board OUT− to ESP32-CAM GND.
- Solder the Li-Po battery wires to the charging board B+ (red) and B− (black). Double-check polarity — reversed Li-Po can vent or catch fire.
- Insert a microSD card into the ESP32-CAM slot.
- Seat the ESP32-CAM into the printed Cage part. The lens points through the front opening.
- Place the Lens bezel over the OV2640 module.
- Tuck the battery into its slot in the Cage.
- Position the USB-C charging board, switch, and shutter button so they line up with their cutouts in the Front/Back halves.
- Sandwich the front and back together. The press-fit should hold them; add a dab of glue at the seam if needed.
- Charge the battery via the USB-C port until the charging LED indicates full.
- Flip the slide switch to ON.
- Watch for the flash LED to blink the boot sequence (1× → 2× → 3× → 4× → 5× → 6×, then 3 fast blinks = ready).
- Connect to the
Charm-CamWi-Fi, open the UI, take your first shot.
Congratulations — you've built a Charm-Cam.
After the first wired flash, you can update the firmware wirelessly via the Firmware Update page in Settings (the OTA path).
- In Arduino IDE: Sketch → Export Compiled Binary.
- Find the binary in the sketch folder — use the file named
esp32cam_camera-v1.2.ino.bin(the plain one, notmerged,bootloader, orpartitions).
- Connect to the
Charm-CamWi-Fi. - Open Settings → Firmware Update.
- Choose the
.ino.binfile and upload. - The device reboots into the new firmware automatically.
- Wrong partition scheme — re-flash via USB with Minimal SPIFFS selected.
- Binary too large for the OTA app slot — strip unused features or use a larger-app partition.
- You uploaded the wrong file — use
*.ino.bin, not*.merged.bin/*.bootloader.bin/*.partitions.bin.
ESP32-CAM boards are sensitive to weak power supplies.
For stable behavior:
- use a good USB cable
- use a solid 5V power source
- avoid unstable or low-current adapters
Brownout or boot issues are often power related. The firmware also lowers Wi-Fi TX power to 8.5 dBm to reduce brownout risk on marginal supplies.
The current firmware lives in esp32cam_camera-v1.2/ and is split across:
esp32cam_camera-v1.2.ino- main sketch (setup, loop, globals, shutter button handling)config.h- pin definitions, default credentials, roll size, button timing, capture rotationhtml_main.h- main web UI (PROGMEM)html_ota.h- OTA update page (PROGMEM)camera.ino- OV2640 camera initstorage.ino- SD card, file ops, roll logic, capture, EXIF rotationpersistence.ino- NVS load/save for settings and roll statehandlers.ino- HTTP request handlers and route registrationled.ino- status and flash LED helpers
A separate diag_test/ sketch is included for hardware diagnostics.
- Settings and roll state are saved in non-volatile storage and survive reboot
- The SD card is required for saving photos and roll archives
- The UI is designed around a film-camera workflow, even when digital mode is enabled
The film canister SVGs in Filmrolls/ reproduce visual elements (logos, color palettes, typography) inspired by real film stocks (Kodak, Ilford, Velvia, etc.). These are included for aesthetic purposes only. All trademarks and brand identities belong to their respective owners. This project is not affiliated with, endorsed by, or sponsored by any film manufacturer.
Released under the MIT License — free to use, modify, and distribute. This is a free hobby project; no warranty.















