Party Cam: Instant Thermal Camera & Digital Gallery
A DIY point-and-shoot that prints dithered lo-fi photos on thermal receipt paper and simultaneously uploads captures to a local Rust web server.
Hardware BOM
| Part | Notes |
|---|---|
| ESP32-CAM (AI-Thinker) | Camera + WiFi module |
| Thermal Printer | TTL serial, 5V–9V |
| 2× 18650 Li-Ion | In series = 7.4V; powers printer directly + 5V buck converter for ESP32 |
| Tactile button | Shutter trigger |
| FTDI adapter or Arduino Uno | For flashing only |
Wiring
| ESP32-CAM Pin | Component | Function |
|---|---|---|
| 5V | PSU 5V | Power in |
| GND | PSU GND | Common ground |
| GPIO 12 | Button | Shutter (other leg → GND) |
| GPIO 14 (U1T) | Printer RX | Data to printer |
| GPIO 15 (U1R) | Printer TX | Data from printer |
| GPIO 4 | Flash LED | Optional built-in flash |
All pin assignments are in include/config.h. Change them there if your wiring differs.
Server Setup
Run the server on any machine on the same local network as the camera. It receives uploads and hosts the gallery.
Option A: Docker Compose (recommended)
cd server
docker compose up -d
Images are saved to server/party_images/ on the host. To change the gallery password, edit GALLERY_PASSWORD in compose.yml.
Option B: Cargo (dev)
cd server
cargo run --release
Requires a .env file in the server/ directory:
SERVER_HOST=0.0.0.0
SERVER_PORT=3000
GALLERY_PASSWORD=partytime
UPLOAD_DIR=./uploads
GALLERY_PASSWORD is required — the server panics at startup without it.
Firmware Setup
1. Configure
Check platformio.ini and make sure board matches your actual hardware. The default is 4d_systems_esp32s3_gen4_r8n16 — change it to ai_thinker_esp32-cam if using a standard ESP32-CAM. Camera pin definitions in include/config.h are pre-set for AI-Thinker.
2. Flash (Arduino Uno as bridge)
Wire the Uno as a passthrough:
- Arduino RESET → Arduino GND (bypasses the Uno chip)
- Arduino Pin 0 (RX) → ESP32 U0R
- Arduino Pin 1 (TX) → ESP32 U0T
- ESP32 IO0 → ESP32 GND (enables download mode)
Click Upload in PlatformIO, then press RST on the ESP32 when "Connecting…" appears.
3. Boot
Disconnect IO0 from GND, press RST. The camera boots.
First Boot Configuration
- Power on. Camera broadcasts WiFi AP:
PartyCam-Setup. - Connect your phone — a captive portal opens automatically (or go to
192.168.4.1). - Select the venue WiFi and enter the password.
- Set the Upload URL to
http://<server-machine-ip>:3000/upload. - Adjust contrast/heat to taste. Save & Reboot.
The portal times out after 3 minutes. If it closes before you save, the camera boots in offline mode (printing still works, upload disabled).
Settings Page
After first boot the settings page is always reachable at:
http://partycam.local
(or the camera's IP address on port 80). Use it to adjust contrast, brightness, flip/mirror, heat density, and the upload URL.
Gallery
http://<server-ip>:3000/gallery
Open from any device on the same network. The browser will prompt for the gallery password. New photos appear automatically — the page polls every 5 seconds.
Customisation
| What | Where |
|---|---|
| Pin assignments | include/config.h |
| Printer baud rate | include/config.h → BAUD_RATE |
| Default camera settings | include/settings_service.h → AppSettings struct defaults |
| Gallery password | compose.yml or .env |
| Capture resolution | src/camera_service.cpp → config.frame_size (update IMAGE_WIDTH/IMAGE_HEIGHT in server/src/main.rs to match) |