Skip to Content

Streaming video con ESP32-CAM

Streaming video con ESP32-CAM

In questo tutorial imparerai come trasmettere video da un ESP32-CAM sulla tua rete Wi‑Fi locale al tuo browser web. Questo ti permetterà, ad esempio, di costruire una telecamera di sorveglianza wireless che puoi monitorare dal tuo computer.

Componenti necessari

Ti servirà un ESP32-CAM per provare gli esempi di codice. Puoi procurarti un ESP32-CAM con un USB-TTL Shield per la programmazione oppure un FTDI USB-TTL Adapter. L’ FTDI USB-TTL Adapter è un po’ più scomodo da usare ma lascia i pin GPIO facilmente accessibili. Per questo tutorial consiglierei l’ USB-TTL Shield, ma assicurati di prendere quello corretto (vedi il Programming the ESP32-CAM tutorial per i dettagli).

ESP32-CAM con USB-TTL Shield

FTDI USB-TTL Adapter

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Streaming video

In questo progetto implementeremo un server di streaming video che gira sull’ESP32-CAM. L’ ESP32-CAM acquisisce immagini e le serve tramite Wi‑Fi. Il router Wi‑Fi trasporta queste immagini al browser web, che le mostra come uno stream video. L’immagine sotto illustra il setup:

Streaming video tramite WiFi locale

Nota che lo stream video non è cifrato né sicuro, ma sarà visibile solo a un URL all’interno della tua rete Wi‑Fi locale, es. 192.168.2.39/stream. Solo chi ha accesso alla tua rete Wi‑Fi potrà vedere lo stream video.

Codice per il server video

Lo sketch Arduino seguente imposta il server di streaming video che invia uno stream MJPEG continuo dalla fotocamera ESP32-CAM a qualsiasi browser web connesso alla stessa rete Wi‑Fi.

Per questo codice useremo la esp32cam libreria, che semplifica la gestione della camera. Puoi installarla tramite il Library Manager nell’ Arduino IDE. Cerca semplicemente “esp32cam” e premi INSTALL. L’immagine sotto mostra l’installazione completata:

esp32cam library installed via Library Manager
Libreria esp32cam installata tramite Library Manager

Di seguito trovi il codice completo per il server di streaming video. Dagli prima un’occhiata veloce e poi ne discuteremo i dettagli:

#include "WebServer.h"
#include "WiFi.h"
#include "esp32cam.h"

const char* WIFI_SSID = "SSID";
const char* WIFI_PASS = "PASSWORD";
const char* URL = "/stream";
const int FRAMERATE = 10;
const auto RESOLUTION = esp32cam::Resolution::find(1024, 768);

WebServer server(80);

void handleStream() {
  static char head[128];
  WiFiClient client = server.client();

  server.sendContent("HTTP/1.1 200 OK\r\n"
                     "Content-Type: multipart/x-mixed-replace; "
                     "boundary=frame\r\n\r\n");

  while (client.connected()) {
    auto frame = esp32cam::capture();
    if (frame) {
      sprintf(head,
              "--frame\r\n"
              "Content-Type: image/jpeg\r\n"
              "Content-Length: %ul\r\n\r\n",
              frame->size());
      client.write(head, strlen(head));
      frame->writeTo(client);
      client.write("\r\n");
    }
    delay(1000 / FRAMERATE);
  }
}

void initCamera() {
  using namespace esp32cam;
  Config cfg;
  cfg.setPins(pins::AiThinker);
  cfg.setResolution(RESOLUTION);
  cfg.setBufferCount(2);
  cfg.setJpeg(80);
  Camera.begin(cfg);
}

void initWifi() {
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
  }
  Serial.printf("Stream at: http://%s%s\n",
                WiFi.localIP().toString().c_str(), URL);
}

void initServer() {
  server.on(URL, handleStream);
  server.begin();
}

void setup() {
  Serial.begin(115200);
  initWifi();
  initCamera();
  initServer();
}

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

Librerie

Lo sketch inizia includendo le librerie necessarie:

#include "WebServer.h"
#include "WiFi.h"
#include "esp32cam.h"

Queste librerie abilitano la funzionalità del server HTTP (WebServer.h), connettività Wi‑Fi (WiFi.h), e il controllo della camera usando l’ESP32-CAM (esp32cam.h).

Costanti

Successivamente vengono definite alcune costanti:

const char* WIFI_SSID = "SSID";
const char* WIFI_PASS = "PASSWORD";
const char* URL = "/stream";
const int FRAMERATE = 10;
const auto RESOLUTION = esp32cam::Resolution::find(1024, 768);

Le WIFI_SSID e WIFI_PASS variabili memorizzano le credenziali per la rete Wi‑Fi. Dovrai sostituire SSID e PASSWORD con i dati di accesso reali della tua rete Wi‑Fi.

Il URL è il percorso su cui verrà servito lo stream video. Puoi cambiarlo con qualsiasi valore tu voglia. Per esempio, “/video” o “/frontdoor”, assicurati solo di mantenere la slash (‘/’) all’inizio.

La FRAMERATE variabile definisce quanti frame al secondo verranno inviati al client. E la RESOLUTION imposta la risoluzione desiderata per la camera usando la esp32cam libreria.

Ecco un elenco dei possibili valori per la risoluzione della camera, anche se a seconda del modello non tutti potrebbero funzionare:

  • 96×96
  • 160×120
  • 128×128
  • 176×144
  • 240×176
  • 240×240
  • 320×240
  • 320×320
  • 400×296
  • 480×320
  • 640×480
  • 800×600
  • 1024×768
  • 1280×720
  • 1280×1024
  • 1600×1200

Puoi stampare l’elenco delle risoluzioni della camera usando la seguente funzione:

void printResolutions() {
  Serial.println("Camera resolutions:");
  for (auto res : esp32cam::Camera.listResolutions()) {
    Serial.printf("%dx%d\n", res.getWidth(), res.getHeight());
  }
}

Nota che la risoluzione influirà sul framerate massimo. Con una risoluzione 1600×1200 non otterrai molto più di 10 fotogrammi al secondo.

Oggetti

La riga seguente crea un oggetto server HTTP che ascolta sulla porta 80. Questo è il nostro web server che fornisce lo stream video.

WebServer server(80);

handleStream

La funzione handleStream() gestisce lo stream video ogni volta che un client accede al percorso /stream:

void handleStream() {
  static char head[128];
  WiFiClient client = server.client();

Questa riga ottiene il client attualmente connesso al server. La risposta viene quindi preparata:

server.sendContent("HTTP/1.1 200 OK\r\n"
                   "Content-Type: multipart/x-mixed-replace; "
                   "boundary=frame\r\n\r\n");

Questo header informa il browser che riceverà uno stream MJPEG multipart, in cui ogni parte è separata da un boundary chiamato frame.

All’interno di un ciclo, la funzione acquisisce un frame dalla camera:

  while (client.connected()) {
    auto frame = esp32cam::capture();

Se un frame viene acquisito con successo, viene costruita un’intestazione che descrive l’immagine JPEG:

    if (frame) {
      sprintf(head,
              "--frame\r\n"
              "Content-Type: image/jpeg\r\n"
              "Content-Length: %ul\r\n\r\n",
              frame->size());
      client.write(head, strlen(head));
      frame->writeTo(client);
      client.write("\r\n");
    }

L’immagine viene inviata al client come JPEG, e il ciclo poi attende brevemente in base al framerate:

delay(1000 / FRAMERATE);

Nota che questa FRAMERATE costante permette soltanto di rallentare il framerate rispetto al massimo che l’ESP32-CAM può produrre per la risoluzione scelta. Se vuoi sempre usare il framerate massimo, rimuovi semplicemente questa riga.

initCamera

La initCamera() funzione configura e avvia l’hardware dell’ESP32-CAM:

void initCamera() {
  using namespace esp32cam;
  Config cfg;
  cfg.setPins(pins::AiThinker);
  cfg.setResolution(RESOLUTION);
  cfg.setBufferCount(2);
  cfg.setJpeg(80);
  Camera.begin(cfg);
}

Qui viene creato un Config oggetto. La setPins funzione configura i pin della camera basandosi sul layout della scheda AiThinker. setResolution definisce la risoluzione da usare, mentre setBufferCount determina quanti buffer immagine vengono usati internamente.

La setJpeg funzione imposta la qualità di compressione JPEG. 80 è un buon compromesso tra qualità e dimensione. 90 offre una qualità migliore ma una riduzione minore delle dimensioni dell’immagine. Per video più veloci puoi ridurre la risoluzione e la compressione JPEG, ma otterrai ovviamente immagini più piccole e di qualità inferiore.

Infine, Camera.begin(cfg) inizializza la camera con queste impostazioni.

initWifi

La initWifi() funzione connette l’ESP32-CAM alla rete Wi‑Fi specificata:

void initWifi() {
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
  }
  Serial.printf("Stream at: http://%s%s\n",
                WiFi.localIP().toString().c_str(), URL);
}

WiFi.persistent(false) disabilita la scrittura delle credenziali nella flash, accelerando la riconnessione. Il dispositivo è impostato su station mode (WIFI_STA), e tenta di connettersi alla rete Wi‑Fi usando le credenziali fornite.

Una volta connesso, l’indirizzo IP e il percorso dello stream vengono stampati sul Serial Monitor. Dovrai copiare e incollare questo URL nel campo indirizzi del tuo browser per vedere lo stream video. L’ URL effettivo dipenderà dal tuo ESP32-CAM ma puoi cambiare il suffisso “stream”. Nel mio caso vedo il seguente URL sul Serial Monitor:

Streaming URL printed to Serial Monitor
URL di streaming stampato sul Serial Monitor

Perciò, copio “http://192.168.2.39/stream” nella barra degli indirizzi del mio browser Chrome per accedere al video.

initServer

La initServer() funzione collega il percorso di streaming all’handler e avvia il server:

void initServer() {
  server.on(URL, handleStream);
  server.begin();
}

Questo mappa qualsiasi richiesta a /stream al handleStream() funzione, e poi avvia il server.

setup

La setup() funzione viene eseguita una sola volta all’avvio:

void setup() {
  Serial.begin(115200);
  initWifi();
  initCamera();
  initServer();
}

Avvia la comunicazione seriale, si connette al Wi‑Fi, inizializza la camera e configura il web server.

loop

Infine, la loop() funzione gestisce continuamente le richieste HTTP in arrivo:

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

Questa riga permette all’ ESP32-CAM di rispondere alle richieste dei client invocando eventuali handler registrati come handleStream().

Nel complesso, questo codice crea un server di streaming MJPEG semplice ma efficace, accessibile da qualsiasi browser web nella stessa rete, fornendo un feed live dalla camera ESP32-CAM.

Per caricare quel codice sul tuo modulo ESP32-CAM, seleziona la AI Thinker ESP32-CAM scheda e poi passa l’ESP32-CAM in modalità download.

Select AI Thinker ESP32-CAM  as board
Seleziona AI Thinker ESP32-CAM come scheda

Se hai bisogno di aiuto, dai un’occhiata al Programming the ESP32-CAM tutorial.

Conclusioni

In questo tutorial hai imparato come trasmettere video da un ESP32-CAM sulla tua rete Wi‑Fi locale al tuo browser web.

Se vuoi rilevare oggetti nello stream video dai un’occhiata al nostro Object Detection with ESP32-CAM and YOLO tutorial. Se vuoi costruire un sistema di sorveglianza attivato dal movimento, il Motion Activated ESP32-CAM tutorial potrebbe essere utile.

Guarda anche il More GPIO pins for ESP32-CAM tutorial, se ti servono più pin GPIO per controllare il tuo sistema di sorveglianza. In alternativa potresti considerare una scheda diversa con più GPIO come la XIAO-ESP32-S3-Sense o la ESP32-WROVER CAM.

Infine, potresti voler accendere il LED flash dell’ ESP32-CAM se usi la camera in un ambiente buio. Dai un’occhiata al Control ESP32-CAM Flash LED tutorial per maggiori dettagli.

Se hai domande, sentiti libero di lasciarle nella sezione commenti.

Buon tinkering ; )