ESP32-CAM: отправка фото на сервер по HTTP POST (PHP + Arduino IDE)

В этом руководстве вы узнаете, как отправлять HTTP POST запросы с платы ESP32-CAM с помощью Arduino IDE для передачи фотографий на сервер. Мы покажем, как отправить JPG-изображение на локальный сервер (LAMP-сервер на Raspberry Pi) или на облачный сервер (к которому можно получить доступ из любой точки мира). Для сохранения изображений на сервере мы используем PHP.

ESP32-CAM отправка фото на локальный или облачный сервер по HTTP POST с Arduino IDE

Обновлено 27 марта 2023

Чтобы собрать этот проект, вам необходимо выполнить следующие шаги. Следуйте инструкциям для LAMP-сервера или хостинга, в зависимости от того, хотите ли вы получать доступ к фотографиям локально или из любой точки мира.

  1. Размещение вашего PHP-приложения

    1. Raspberry Pi LAMP Server (локальный доступ)

    2. Хостинг-сервер (доступ из любой точки мира)

  2. PHP-скрипты для сохранения и отображения фотографий на сервере

    1. Raspberry Pi LAMP Server (локальный доступ)

    2. Хостинг-сервер (доступ из любой точки мира)

  3. Программирование ESP32-CAM в Arduino IDE

  4. Тестирование и финальная демонстрация

1. Размещение вашего PHP-приложения

Цель этого проекта — иметь локальный или облачный сервер для хранения и доступа к фотографиям с ESP32-CAM.

1. Локальный сервер на Raspberry Pi:

С LAMP-сервером на Raspberry Pi вы можете получить доступ к своим изображениям локально (как показано ниже).

ESP32-CAM отправка фото на LAMP-сервер Raspberry Pi

Настройка локального LAMP-сервера на RPi >>

2. Облачный сервер (хостинг)

Вы также можете просматривать фотографии ESP32-CAM из любой точки мира, подключившись к собственному серверу и домену. Вот общая схема работы:

ESP32-CAM отправка фото на облачный сервер
  • Bluehost (удобный с cPanel): бесплатное доменное имя при подписке на 3-летний план. Рекомендуется выбрать опцию неограниченного количества сайтов. Обратите внимание, что любой хостинг, поддерживающий PHP, подойдёт для этого урока.

При покупке хостинг-аккаунта вам также нужно будет приобрести доменное имя. Именно это делает проект интересным: вы сможете перейти по своему домену (http://example.com) и увидеть фотографии с ESP32-CAM.

2.1. Подготовка файла .php и папки uploads (LAMP-сервер на Raspberry Pi)

Этот раздел описывает подготовку файла .php и папки uploads для LAMP-сервера на Raspberry Pi. Если вы используете свой собственный сервер + доменное имя, переходите к следующему разделу.

Имея Raspberry Pi с Apache и PHP, в терминале Raspberry Pi перейдите в каталог /var/www/html/:

pi@raspberrypi:~ $ cd /var/www/html/

Создайте новую папку uploads:

pi@raspberrypi:/var/www/html $ mkdir uploads
pi@raspberrypi:/var/www/html $ ls
uploads

В данный момент /var/www/html принадлежит пользователю root, используйте следующие команды для смены владельца на пользователя pi и предоставления всех прав, чтобы позже можно было сохранять фотографии с помощью PHP-скрипта.

sudo chown -R pi:pi /var/www/html
chmod -R 777 /var/www/html/

Наконец, создайте новый файл upload.php:

pi@raspberrypi:/var/www/html $ nano upload.php

Этот PHP-скрипт отвечает за приём входящих изображений от ESP32-CAM, переименование изображений с временной меткой и сохранение их в папке uploads. Отредактируйте созданный файл (upload.php) и скопируйте следующий фрагмент:

<?php
// Rui Santos
// Complete project details at https://RandomNerdTutorials.com/esp32-cam-post-image-photo-server/
// Code Based on this example: w3schools.com/php/php_file_upload.asp

$target_dir = "uploads/";
$datum = mktime(date('H')+0, date('i'), date('s'), date('m'), date('d'), date('y'));
$target_file = $target_dir . date('Y.m.d_H:i:s_', $datum) . basename($_FILES["imageFile"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));

// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
  $check = getimagesize($_FILES["imageFile"]["tmp_name"]);
  if($check !== false) {
    echo "File is an image - " . $check["mime"] . ".";
    $uploadOk = 1;
  }
  else {
    echo "File is not an image.";
    $uploadOk = 0;
  }
}

// Check if file already exists
if (file_exists($target_file)) {
  echo "Sorry, file already exists.";
  $uploadOk = 0;
}

// Check file size
if ($_FILES["imageFile"]["size"] > 500000) {
  echo "Sorry, your file is too large.";
  $uploadOk = 0;
}

// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
  echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
  $uploadOk = 0;
}

// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
  echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
}
else {
  if (move_uploaded_file($_FILES["imageFile"]["tmp_name"], $target_file)) {
    echo "The file ". basename( $_FILES["imageFile"]["name"]). " has been uploaded.";
  }
  else {
    echo "Sorry, there was an error uploading your file.";
  }
}
?>

Посмотреть исходный код

Сохраните файл и выйдите (Ctrl+X, Y и Enter):

2.2. Подготовка файлов .php и папки uploads (хостинг-сервис)

Если вы предпочитаете запускать сервер удалённо и получать доступ к фотографиям из любой точки мира, вам нужен хостинг-аккаунт. После регистрации на хостинге и настройки доменного имени, вы можете войти в cPanel или аналогичную панель управления. После этого откройте File Manager.

Откройте вкладку «Advanced» и выберите «File Manager»:

Bluehost открытие Advanced и File Manager для создания upload.php

Затем выберите public_html. Нажмите кнопку «+ File», чтобы создать новый файл upload.php и новый файл gallery.php. Затем нажмите кнопку «+Folder», чтобы создать папку Uploads.

ESP32-CAM CPanel создание новых PHP-файлов и папки Uploads

После создания трёх элементов отредактируйте файл upload.php:

Новые файлы PHP cPanel и папка uploads созданы

Этот PHP-скрипт отвечает за приём входящих изображений от ESP32-CAM, переименование изображений с временной меткой и сохранение их в папке uploads. Отредактируйте созданный файл (upload.php) и скопируйте фрагмент ниже. Сохраните файл и выйдите.

<?php
// Rui Santos
// Complete project details at https://RandomNerdTutorials.com/esp32-cam-post-image-photo-server/
// Code Based on this example: w3schools.com/php/php_file_upload.asp

$target_dir = "uploads/";
$datum = mktime(date('H')+0, date('i'), date('s'), date('m'), date('d'), date('y'));
$target_file = $target_dir . date('Y.m.d_H:i:s_', $datum) . basename($_FILES["imageFile"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));

// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
  $check = getimagesize($_FILES["imageFile"]["tmp_name"]);
  if($check !== false) {
    echo "File is an image - " . $check["mime"] . ".";
    $uploadOk = 1;
  }
  else {
    echo "File is not an image.";
    $uploadOk = 0;
  }
}

// Check if file already exists
if (file_exists($target_file)) {
  echo "Sorry, file already exists.";
  $uploadOk = 0;
}

// Check file size
if ($_FILES["imageFile"]["size"] > 500000) {
  echo "Sorry, your file is too large.";
  $uploadOk = 0;
}

// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
  echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
  $uploadOk = 0;
}

// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
  echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
}
else {
  if (move_uploaded_file($_FILES["imageFile"]["tmp_name"], $target_file)) {
    echo "The file ". basename( $_FILES["imageFile"]["name"]). " has been uploaded.";
  }
  else {
    echo "Sorry, there was an error uploading your file.";
  }
}
?>

Посмотреть исходный код

3. ESP32-CAM: отправка изображений/фотографий на сервер по HTTP POST

Теперь, когда ваш сервер готов (LAMP-сервер на Raspberry Pi или облачный сервер), пора подготовить ESP32-CAM с кодом для публикации нового изображения на сервер каждые 30 секунд. Прежде чем продолжить этот урок, убедитесь, что выполнены следующие предварительные условия.

Необходимые компоненты

Для выполнения этого урока вам понадобятся следующие компоненты:

Arduino IDE

Мы будем программировать ESP32-CAM с помощью Arduino IDE, поэтому убедитесь, что у вас установлено дополнение ESP32.

Проверка PHP URL

Попробуйте открыть локальный IP-адрес Raspberry Pi или ваше внешнее доменное имя example.com, добавив /upload.php — должно отобразиться:

Sorry, only JPG, JPEG, PNG & GIF files are allowed.Sorry, your file was not uploaded.
ESP32-CAM тестирование URL upload.php

Если вы видите это сообщение, сохраните URL/доменное имя и путь — ваш сервер должен быть готов и вы можете продолжить.

Код ESP32-CAM

Если вы используете локальный сервер без TLS/SSL, или облачный сервер, который не поддерживает HTTPS, используйте код HTTP POST запроса.

Если вы используете облачный сервер, требующий HTTPS-запросы, используйте этот код: код HTTPS POST запроса.

ESP32-CAM HTTP POST запрос

Следующий скетч отправляет изображение на сервер с помощью HTTP POST. Скопируйте код ниже в Arduino IDE.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-cam-post-image-photo-server/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Arduino.h>
#include <WiFi.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

String serverName = "192.168.1.XXX";   // REPLACE WITH YOUR Raspberry Pi IP ADDRESS
//String serverName = "example.com";   // OR REPLACE WITH YOUR DOMAIN NAME

String serverPath = "/upload.php";     // The default serverPath should be upload.php

const int serverPort = 80;

WiFiClient client;

// CAMERA_MODEL_AI_THINKER
#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 int timerInterval = 30000;    // time between each HTTP POST image
unsigned long previousMillis = 0;   // last time image was sent

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("ESP32-CAM IP Address: ");
  Serial.println(WiFi.localIP());

  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_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_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;

  // init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 10;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_CIF;
    config.jpeg_quality = 12;  //0-63 lower number means higher quality
    config.fb_count = 1;
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    delay(1000);
    ESP.restart();
  }

  sendPhoto();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= timerInterval) {
    sendPhoto();
    previousMillis = currentMillis;
  }
}

String sendPhoto() {
  String getAll;
  String getBody;

  camera_fb_t * fb = NULL;
  fb = esp_camera_fb_get();
  if(!fb) {
    Serial.println("Camera capture failed");
    delay(1000);
    ESP.restart();
  }

  Serial.println("Connecting to server: " + serverName);

  if (client.connect(serverName.c_str(), serverPort)) {
    Serial.println("Connection successful!");
    String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
    String tail = "\r\n--RandomNerdTutorials--\r\n";

    uint32_t imageLen = fb->len;
    uint32_t extraLen = head.length() + tail.length();
    uint32_t totalLen = imageLen + extraLen;

    client.println("POST " + serverPath + " HTTP/1.1");
    client.println("Host: " + serverName);
    client.println("Content-Length: " + String(totalLen));
    client.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
    client.println();
    client.print(head);

    uint8_t *fbBuf = fb->buf;
    size_t fbLen = fb->len;
    for (size_t n=0; n<fbLen; n=n+1024) {
      if (n+1024 < fbLen) {
        client.write(fbBuf, 1024);
        fbBuf += 1024;
      }
      else if (fbLen%1024>0) {
        size_t remainder = fbLen%1024;
        client.write(fbBuf, remainder);
      }
    }
    client.print(tail);

    esp_camera_fb_return(fb);

    int timoutTimer = 10000;
    long startTimer = millis();
    boolean state = false;

    while ((startTimer + timoutTimer) > millis()) {
      Serial.print(".");
      delay(100);
      while (client.available()) {
        char c = client.read();
        if (c == '\n') {
          if (getAll.length()==0) { state=true; }
          getAll = "";
        }
        else if (c != '\r') { getAll += String(c); }
        if (state==true) { getBody += String(c); }
        startTimer = millis();
      }
      if (getBody.length()>0) { break; }
    }
    Serial.println();
    client.stop();
    Serial.println(getBody);
  }
  else {
    getBody = "Connection to " + serverName +  " failed.";
    Serial.println(getBody);
  }
  return getBody;
}

Посмотреть исходный код

ESP32-CAM HTTPS POST запрос

Следующий скетч отправляет изображение на сервер с помощью HTTPS POST. Скопируйте код ниже в Arduino IDE.

/*
  Rui Santos
  Complete project details at:
  https://RandomNerdTutorials.com/esp32-cam-http-post-php-arduino/
  https://RandomNerdTutorials.com/esp32-cam-post-image-photo-server/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

String serverName = "example.com";   //REPLACE WITH YOUR DOMAIN NAME

String serverPath = "/upload.php";     // The default serverPath should be upload.php

const int serverPort = 443; //server port for HTTPS

WiFiClientSecure client;

// CAMERA_MODEL_AI_THINKER
#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 int timerInterval = 30000;    // time between each HTTP POST image
unsigned long previousMillis = 0;   // last time image was sent

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("ESP32-CAM IP Address: ");
  Serial.println(WiFi.localIP());

  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_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_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;

  // init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 10;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_CIF;
    config.jpeg_quality = 12;  //0-63 lower number means higher quality
    config.fb_count = 1;
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    delay(1000);
    ESP.restart();
  }

  sendPhoto();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= timerInterval) {
    sendPhoto();
    previousMillis = currentMillis;
  }
}

String sendPhoto() {
  String getAll;
  String getBody;

  camera_fb_t * fb = NULL;
  fb = esp_camera_fb_get();
  if(!fb) {
    Serial.println("Camera capture failed");
    delay(1000);
    ESP.restart();
  }

  Serial.println("Connecting to server: " + serverName);

  client.setInsecure(); //skip certificate validation
  if (client.connect(serverName.c_str(), serverPort)) {
    Serial.println("Connection successful!");
    String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
    String tail = "\r\n--RandomNerdTutorials--\r\n";

    uint32_t imageLen = fb->len;
    uint32_t extraLen = head.length() + tail.length();
    uint32_t totalLen = imageLen + extraLen;

    client.println("POST " + serverPath + " HTTP/1.1");
    client.println("Host: " + serverName);
    client.println("Content-Length: " + String(totalLen));
    client.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
    client.println();
    client.print(head);

    uint8_t *fbBuf = fb->buf;
    size_t fbLen = fb->len;
    for (size_t n=0; n<fbLen; n=n+1024) {
      if (n+1024 < fbLen) {
        client.write(fbBuf, 1024);
        fbBuf += 1024;
      }
      else if (fbLen%1024>0) {
        size_t remainder = fbLen%1024;
        client.write(fbBuf, remainder);
      }
    }
    client.print(tail);

    esp_camera_fb_return(fb);

    int timoutTimer = 10000;
    long startTimer = millis();
    boolean state = false;

    while ((startTimer + timoutTimer) > millis()) {
      Serial.print(".");
      delay(100);
      while (client.available()) {
        char c = client.read();
        if (c == '\n') {
          if (getAll.length()==0) { state=true; }
          getAll = "";
        }
        else if (c != '\r') { getAll += String(c); }
        if (state==true) { getBody += String(c); }
        startTimer = millis();
      }
      if (getBody.length()>0) { break; }
    }
    Serial.println();
    client.stop();
    Serial.println(getBody);
  }
  else {
    getBody = "Connection to " + serverName +  " failed.";
    Serial.println(getBody);
  }
  return getBody;
}

Посмотреть исходный код

Подробнее об HTTPS-запросах с ESP32: ESP32 HTTPS Requests (Arduino IDE).

Ввод сетевых учётных данных, камеры и параметров сервера

Перед загрузкой кода вам необходимо ввести свои сетевые учётные данные в следующие переменные:

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Убедитесь, что вы выбрали правильную модель камеры. В данном случае мы используем модель AI-THINKER. Если вы используете другую модель камеры, вы можете прочитать это руководство по назначению пинов ESP32-CAM.

Добавьте IP-адрес вашего Raspberry Pi или используйте доменное имя сервера:

String serverName = "192.168.1.XXX";   // REPLACE WITH YOUR Raspberry Pi IP ADDRESS
//String serverName = "example.com";   // OR REPLACE WITH YOUR DOMAIN NAME
String serverPath = "/upload.php";     // The default serverPath should be upload.php

Загрузка кода в ESP32-CAM

Теперь вы можете загрузить код на плату ESP32-CAM. Подключите плату ESP32-CAM к компьютеру с помощью FTDI программатора.

Следуйте схеме подключения:

ESP32-CAM подключение к FTDI программатору для загрузки программы через Arduino IDE

Многие FTDI программаторы имеют перемычку для выбора 3.3V или 5V. Убедитесь, что перемычка установлена в правильное положение для выбора 5V.

Важно: GPIO 0 должен быть подключён к GND, чтобы можно было загрузить код.

ESP32-CAM

FTDI Programmer

GND

GND

5V

VCC (5V)

U0R

TX

U0T

RX

GPIO 0

GND

Чтобы загрузить код, выполните следующие шаги:

  1. Перейдите в Tools > Board и выберите AI-Thinker ESP32-CAM.

  2. Перейдите в Tools > Port и выберите COM-порт, к которому подключён ESP32.

  3. Затем нажмите кнопку загрузки, чтобы загрузить код.

  4. Когда вы увидите точки в окне отладки, как показано ниже, нажмите встроенную кнопку RST на ESP32-CAM.

ESP32-CAM загрузка скетча нажмите кнопку RESET

Через несколько секунд код должен быть успешно загружен на вашу плату.

Если у вас возникли проблемы с загрузкой кода, прочитайте руководство по устранению неполадок ESP32-CAM.

Как работает код

Вот краткое объяснение того, как работает код:

  • Импорт всех библиотек;

  • Определение необходимых переменных;

  • Определение пинов камеры;

  • В setup() устанавливается Wi-Fi соединение и инициализируется камера ESP32.

  • loop() содержит таймер, который вызывает функцию sendPhoto() каждые 30 секунд. Вы можете изменить это время задержки в переменной timerInterval.

Функция sendPhoto() — это часть, которая фактически делает фото и отправляет его на ваш сервер. Вы можете использовать эту функцию в других своих проектах, которые требуют съёмки и публикации фото на сервер.

4. Тестирование и финальная демонстрация

После загрузки кода на плату откройте монитор порта Arduino IDE — вы должны увидеть подобное сообщение, выводимое каждые 30 секунд:

The file esp32-cam.jpg has been uploaded.
ESP32-CAM файл загружен, тестирование проекта в мониторе порта Arduino IDE

Если вы перейдёте по URL вашего локального сервера http://IP-Address/uploads или по URL облачного сервера http://example.com/uploads, вы увидите папку со всеми сохранёнными фотографиями.

ESP32-CAM папка Uploads с сохранёнными изображениями на сервере

Вы можете нажать на каждую ссылку, чтобы открыть новую страницу с полным изображением:

ESP32-CAM загрузка фото на сервер PHP Arduino IDE

Заключение

Вот и всё! Теперь вы можете отправлять фотографии ESP32-CAM на любой сервер с помощью HTTP POST. Модифицируйте этот проект под свои нужды, например, делайте фото и отправляйте на сервер при обнаружении движения.

Другие уроки по ESP32, которые могут быть вам интересны: