ESP32-CAM Überwachungskamera mit Bewegungserkennung selber bauen: Video-Streaming & Fotoauslösung

Eine eigene Überwachungskamera für ein paar Euro? Mit dem ESP32-CAM ist das kein Problem. In diesem Tutorial baust du einen WLAN-Live-Videostream auf, richtest eine Bewegungserkennung mit externem PIR-Sensor ein und speicherst automatisch Schnappschüsse auf Micro-SD-Karte, sobald sich etwas vor der Linse bewegt.

Warum das ESP32-CAM Set der perfekte Einstieg ist

Das ESP32-CAM vereint einen vollwertigen ESP32-Mikrocontroller mit WLAN, Bluetooth und einer OV2640-Kameraeinheit (2 Megapixel) auf einer einzigen, extrem kompakten Platine – für unter 12 Euro. Anders als ein reines Entwicklungsboard bringt es alles mit, was für ein Kamera-Projekt nötig ist: einen Kamera-Anschluss, einen Micro-SD-Kartenslot für lokale Speicherung und genug Rechenleistung, um JPEG-Bilder direkt auf dem Chip zu komprimieren und per WLAN zu streamen.

Der einzige Wermutstropfen: Das reine ESP32-CAM-Modul hat keinen USB-Anschluss zum Programmieren. Deshalb ist die CH340G-Basisplatine im MAKEROO-Set so praktisch – sie steckt das Kameramodul auf und stellt einen USB-C-Anschluss samt automatischer Boot/Reset-Schaltung bereit, sodass du direkt aus der Arduino IDE flashen kannst, ohne Kabel umzustecken.

Typische Einsatzgebiete: eine Türspion-Kamera, ein Vogelhäuschen-Beobachter, eine Werkstatt-Überwachung oder ein einfaches Zeitraffer-System für 3D-Drucke – überall dort, wo eine kabellose, günstige Kamera mit Bewegungsauslöser gebraucht wird.

Was du brauchst

Bauteil Menge ca. Preis Link
ESP32-CAM Set mit CH340G Basisplatine & 2.4G Antenne 1x ab 11,99 € Zum Produkt
HC-SR501 PIR Bewegungsmelder Modul 1x ab 2,49 € Zum Produkt
Breadboard 400 Kontakte 1x ab 3,49 € Zum Produkt
22AWG Kabel 2-adrig (für feste Verbindungen) 1x Meterware ab 0,99 € Zum Produkt
Micro-SD-Karte (FAT32 formatiert, max. 32GB) 1x eigenes Zubehör

💡 Zum Flashen: Die CH340G-Basisplatine übernimmt die USB-Kommunikation komplett, du brauchst keinen separaten FTDI-Adapter. Wichtig ist nur, dass du beim Hochladen den IO0-Taster auf der Basisplatine gedrückt hältst, bis der Upload startet (Boot-Modus) – danach einmal die Reset-Taste drücken, um das Programm zu starten.

Vorbereitung in der Arduino IDE

Füge in den Voreinstellungen der Arduino IDE unter „Zusätzliche Boardverwalter-URLs" die ESP32-Paketquelle hinzu und installiere über den Boardverwalter das Paket esp32 by Espressif Systems. Wähle anschließend als Board AI Thinker ESP32-CAM aus. Diese Boardauswahl setzt automatisch die richtigen Kamera-Pins und die Partitionstabelle (mit ausreichend Speicher fürs Kamerabild).

PIR-Sensor Pin ESP32-CAM Pin Funktion
VCC 5V Spannungsversorgung
GND GND Masse
OUT GPIO 13 Bewegungssignal (HIGH bei Erkennung)

⚠️ GPIO-Belegung beachten: Das ESP32-CAM nutzt fast alle Pins für die Kamera und die SD-Karte im 1-Bit-Modus. Frei nutzbare Pins sind unter anderem GPIO 12, 13, 14, 15 und 16 – bei GPIO 0 musst du zusätzlich aufpassen, da er den Boot-Modus bestimmt und beim normalen Betrieb unbeschaltet bleiben sollte.

Code 1: Live-Videostream im Browser

Der einfachste Einstieg: Das ESP32-CAM baut ein eigenes WLAN-Stream-Interface auf, das du mit jedem Browser im Heimnetzwerk öffnen kannst.

#include <WiFi.h>
#include <esp_camera.h>
#include <WebServer.h>

// AI-Thinker ESP32-CAM Pinbelegung
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27
#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

const char* ssid = "DEIN_WLAN_NAME";
const char* password = "DEIN_WLAN_PASSWORT";

WebServer server(80);

void startKamera() {
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_VGA;
  config.jpeg_quality = 12;
  config.fb_count = 1;

  esp_camera_init(&config);
}

void handleJpg() {
  camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    server.send(503, "text/plain", "Kamera nicht bereit");
    return;
  }
  server.setContentLength(fb->len);
  server.send(200, "image/jpeg", "");
  server.sendContent((const char*)fb->buf, fb->len);
  esp_camera_fb_return(fb);
}

void handleRoot() {
  String html = ""
                "location.reload(),300)\">"
                "";
  server.send(200, "text/html", html);
}

void setup() {
  Serial.begin(115200);
  startKamera();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("Kamera bereit! Aufruf unter: http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/jpg", handleJpg);
  server.begin();
}

void loop() {
  server.handleClient();
}

Nach dem Hochladen zeigt der serielle Monitor die IP-Adresse des ESP32-CAM an. Öffne diese im Browser, und die Seite lädt automatisch alle 300ms ein neues Bild nach – ein simples, aber funktionierendes „Pseudo-Streaming" ganz ohne zusätzliche Bibliotheken.

Code 2: Bewegungserkennung mit Foto-Speicherung auf SD-Karte

Jetzt kombinierst du den PIR-Sensor mit der Kamera: Bei erkannter Bewegung macht das ESP32-CAM automatisch ein Foto und speichert es mit Zeitstempel im Dateinamen auf der Micro-SD-Karte.

#include "esp_camera.h"
#include "SD_MMC.h"
#include "time.h"

#define PIR_PIN 13

// Kamera-Pins wie in Code 1 (startKamera-Funktion wiederverwenden)
void startKamera();

int bildZaehler = 0;

void speichereFoto() {
  camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Fehler: Kein Kamerabild erhalten");
    return;
  }

  String pfad = "/foto_" + String(bildZaehler) + ".jpg";
  File datei = SD_MMC.open(pfad.c_str(), FILE_WRITE);

  if (!datei) {
    Serial.println("Fehler beim Öffnen der Datei auf SD-Karte");
  } else {
    datei.write(fb->buf, fb->len);
    Serial.print("Foto gespeichert: ");
    Serial.println(pfad);
    bildZaehler++;
  }

  datei.close();
  esp_camera_fb_return(fb);
}

void setup() {
  Serial.begin(115200);
  pinMode(PIR_PIN, INPUT);

  startKamera();

  if (!SD_MMC.begin()) {
    Serial.println("SD-Karte konnte nicht initialisiert werden!");
    return;
  }
  Serial.println("Bereit. Warte auf Bewegung...");
}

void loop() {
  if (digitalRead(PIR_PIN) == HIGH) {
    Serial.println("Bewegung erkannt! Nehme Foto auf...");
    speichereFoto();
    delay(5000); // Sperrzeit, damit nicht dutzende Fotos pro Sekunde entstehen
  }
}

Die SD_MMC-Bibliothek nutzt den 1-Bit-SDIO-Modus, den das ESP32-CAM fest verdrahtet für den Kartenslot bereitstellt – dadurch ist keine zusätzliche Verkabelung nötig, die Karte muss nur eingesteckt werden. Die 5-Sekunden-Sperrzeit nach jeder Aufnahme verhindert, dass die SD-Karte bei anhaltender Bewegung sofort vollläuft.

Code 3: Foto per HTTP an einen Server senden

Statt (oder zusätzlich zur) lokalen Speicherung kannst du das Bild bei Bewegung auch direkt an einen eigenen Server oder ein Heimautomatisierungssystem (z. B. Home Assistant) senden.

#include <WiFi.h>
#include <HTTPClient.h>
#include "esp_camera.h"

#define PIR_PIN 13
const char* ssid = "DEIN_WLAN_NAME";
const char* password = "DEIN_WLAN_PASSWORT";
const char* serverUrl = "http://192.168.1.50:8080/upload"; // eigener Server im lokalen Netz

void startKamera();

void sendeFotoPerHttp() {
  camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Kein Kamerabild erhalten");
    return;
  }

  HTTPClient http;
  http.begin(serverUrl);
  http.addHeader("Content-Type", "image/jpeg");

  int httpCode = http.POST(fb->buf, fb->len);
  Serial.print("Server-Antwort: ");
  Serial.println(httpCode);

  http.end();
  esp_camera_fb_return(fb);
}

void setup() {
  Serial.begin(115200);
  pinMode(PIR_PIN, INPUT);
  startKamera();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  Serial.println("Verbunden, warte auf Bewegung...");
}

void loop() {
  if (digitalRead(PIR_PIN) == HIGH) {
    Serial.println("Bewegung erkannt, sende Foto...");
    sendeFotoPerHttp();
    delay(5000);
  }
}

Auf der Empfängerseite genügt ein einfacher HTTP-Server (z. B. ein kleines Python-Flask-Skript), der die POST-Anfrage mit dem JPEG-Binärkörper entgegennimmt und abspeichert oder weiterverarbeitet – etwa um eine Push-Benachrichtigung auszulösen.

Praxistipps

📶 Stabile Stromversorgung: WLAN-Übertragung und Kamerablitz (falls per LED-Blitz nachgerüstet) ziehen kurzzeitig deutlich mehr Strom als ein normales Sensor-Projekt. Nutze ein solides 5V/1A-Netzteil statt eines schwachen USB-Ladegeräts, um sporadische Reboots zu vermeiden.

🖼️ Auflösung anpassen: FRAMESIZE_VGA (640x480) ist ein guter Kompromiss aus Bildqualität und Geschwindigkeit. Für schnelleres Streaming reduzierst du auf FRAMESIZE_QVGA, für Detailaufnahmen erhöhst du auf FRAMESIZE_SVGA oder FRAMESIZE_UXGA – höhere Auflösungen brauchen aber mehr freien PSRAM.

🔋 PIR-Empfindlichkeit einstellen: Die zwei Potentiometer auf dem HC-SR501-Modul regeln Empfindlichkeit und Nachlaufzeit. Für eine Türüberwachung lohnt sich eine kurze Nachlaufzeit, für Gartenüberwachung eher eine größere Reichweite mit geringerer Empfindlichkeit gegen Blattbewegungen.

Troubleshooting

⚠️ „Brownout detector was triggered" beim Start: Das klassische ESP32-CAM-Problem – die Stromversorgung über den USB-Port des Computers reicht beim Kamerastart oft nicht aus. Nutze ein separates 5V-Netzteil oder ein hochwertiges USB-Kabel mit dickeren Adern.

⚠️ Upload schlägt fehl / Board reagiert nicht: Halte den IO0-Taster auf der CH340G-Basisplatine während des kompletten Upload-Vorgangs gedrückt (loslassen erst, wenn „Connecting..." im Ausgabefenster verschwunden ist), und drücke danach einmal Reset.

⚠️ Kamera-Init schlägt fehl (Fehlercode 0x105/ESP_ERR_NOT_FOUND): Meist ein Wackelkontakt zwischen Kameramodul und Basisplatine. Prüfe, ob der Flachbandstecker der Kamera vollständig und richtig herum eingerastet ist.

📷 Baue deine eigene WLAN-Kamera

Alle Bauteile für dieses Tutorial findest du bei MAKEROO.

Kombiniere die Bewegungserkennung mit unserem PIR-Alarmanlagen-Tutorial für ein komplettes Überwachungssystem mit Sirene und Foto-Beweis.

Fazit

Mit dem ESP32-CAM Set baust du für unter 20 Euro eine vollwertige WLAN-Kamera mit Live-Stream, Bewegungserkennung und lokaler oder Netzwerk-Speicherung. Vom einfachen Browser-Stream über die automatische Foto-Auslösung per PIR-Sensor bis zum Versand ans eigene Heimnetzwerk deckt dieses Tutorial die komplette Bandbreite ab – die perfekte Basis für dein eigenes Überwachungs- oder Beobachtungsprojekt.

Zurück zum Blog