← How-Tos
electronics Jul 3, 2026 ◯ 2 min read

ESP32-CAM Motion Detection & Snapshot-to-Cloud

esp32 cammotion detectioncloudsnapshot

Two Ways to Detect Motion

For most projects, PIR + camera is the more reliable and simpler combination — this guide focuses on that approach.

Wiring a PIR Sensor

ESP32-CAM has limited free GPIO (most pins are committed to the camera interface) — GPIO 13 or GPIO 12 are commonly available depending on your specific board's exact pinout; check your board's silkscreen/documentation, since AI-Thinker variants can differ slightly.

Basic Motion-Triggered Capture Code

#define PIR_PIN 13 void setup() { pinMode(PIR_PIN, INPUT); // ... standard camera init from the setup guide ... } void loop() { if (digitalRead(PIR_PIN) == HIGH) { camera_fb_t* fb = esp_camera_fb_get(); if (fb) { uploadToCloud(fb->buf, fb->len); esp_camera_fb_return(fb); } delay(5000); // debounce — avoid spamming captures during continued motion } }

Uploading to Cloud Storage

Simplest reliable option: HTTP POST to a webhook/storage endpoint. If you're already running Home Assistant (see the HA setup guide), it can receive and store these directly, or trigger a notification with the image attached, without needing separate third-party cloud storage at all:

void uploadToCloud(uint8_t* imageData, size_t len) { HTTPClient http; http.begin("http://your-ha-instance:8123/api/webhook/motion_snapshot"); http.addHeader("Content-Type", "image/jpeg"); http.POST(imageData, len); http.end(); }

Reducing False Triggers

Battery/Low-Power Considerations

If this is running on battery rather than continuous power, put the ESP32 into deep sleep between PIR triggers using the PIR output as a wake source (esp_sleep_enable_ext0_wakeup) — see the dedicated ESP32 deep sleep guide for the full pattern. Continuous polling as shown above is fine for mains-powered installs but drains a battery fast.