ESP32-CAM with Telegram: Take Photos, Control Outputs, Request Sensor Readings and Motion Notifications

In this project we’ll create a PCB shield for the ESP32-CAM AI-Thinker board with a PIR motion sensor, a BME280 temperature, humidity and pressure sensor and some additional exposed pins. We’ll create a Telegram bot for the ESP32-CAM that allows you to control your board from anywhere to request a photo, sensor readings or control the flash. Additionally, you’ll receive a notification with a new photo whenever motion is detected.

Control ESP32-CAM with Telegram Take Photos, Control Outputs, Request Sensor Readings and Motion Notifications

Alternatively, you can also follow this project by wiring the circuit on a breadboard.

Watch the Video Tutorial

This project is available in video format and in written format. You can watch the video below or you can scroll down for the written instructions.

Resources

You can find all the resources needed to build this project in the links below (or you can visit the GitHub project):

Project Overview

This project consists of three parts:

  1. Designing and Building the PCB shield
  2. Creating the Telegram Bot
  3. Programming the PCB shield using Arduino IDE

ESP32-CAM PCB Shield Features

The PCB shield is designed to be stacked to the ESP32-CAM. For this reason, if you want to use our PCB, you need the same ESP32-CAM board. We’re using the ESP32-CAM AI-Thinker Module.

ESP32-CAM AI Thinker Module Shield PCB Parts Components Mounted

We’re also using a camera module with a longer ribbon. So that when you mount the shield, the camera is on the same side of the PIR motion sensor.

Alternatively, you can also assemble the circuit on a breadboard.

ESP32-CAM Project Telegram Test Circuit Diagram Breadboard Wiring

The shield consists of:

  • BME280 temperature, humidity and pressure sensor (4 pins);
  • Mini PIR motion sensor (AM312);
  • Exposed 5V and GND pins to power up the shield and ESP32-CAM;
  • Other exposed GPIOs if you want to add additional features.

ESP32-CAM PCB Shield Pin Assignment

This is the pin assignment for the BME280 and PIR motion sensor on the PCB shield:

  • PIR Motion Sensor: GPIO 13
  • BME280: GPIO 14 (SDA), GPIO 15 (SCL)

ESP32-CAM Telegram Bot

To control the ESP32-CAM shield, we’ll create a Telegram bot, so that you can monitor your ESP32-CAM from anywhere (as long as you have internet access in your smartphone). You can use the following commands to interact with your bot:

  • /start: sends a welcome message with the valid commands to control the shield;
  • /flash: toggles the ESP32-CAM LED Flash;
  • /photo: takes a new photo and sends it to your Telegram account;
  • /readings: requests the latest BME280 sensor readings.
Control ESP32-CAM with Telegram Take Photos Control Outputs Request Sensor Readings and Motion Notifications Demonstration

Additionally, you’ll receive a notification with a photo whenever motion is detected. Finally, only you (or any other authorized user that you want) can control the ESP32-CAM using Telegram.

Testing the Circuit on a Breadboard

Before designing and building the PCB shield, it’s important to test the circuit on a breadboard. If you don’t want to make a PCB, you can still follow this project by assembling the circuit on a breadboard.

ESP32-CAM Project Telegram Test Circuit Diagram Breadboard Wiring

Parts Required

To assemble the circuit on a breadboard you need the following parts:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

After gathering all the parts, assemble the circuit by following the next schematic diagram:

ESP32-CAM with BME280 and PIR Motion Sensor Wiring Schematic Diagram

Designing the PCB

To design the circuit and PCB, we used EasyEDA which is a browser based software to design PCBs. If you want to customize your PCB, you just need to upload the following files:

Designing the circuit works like in any other circuit software tool, you place some components and you wire them together. Then, you assign each component to a footprint.

ESP32-CAM PCB Shield Circuit Diagram Telegram Take Photo PIR BME280

Having the parts assigned, place each component. When you’re happy with the layout, make all the connections and route your PCB.

ESP32-CAM PCB Shield Telegram Tale Photo PIR BME280

Save your project and export the Gerber files.

Note: you can grab the project files and edit them to customize the shield for your own needs.

Ordering the PCBs at PCBWay

This project is sponsored by PCBWay. PCBWay is a full feature Printed Circuit Board manufacturing service.

Ordering the PCBs at PCBWay

Turn your DIY breadboard circuits into professional PCBs – get 10 boards for approximately $5 + shipping (which will vary depending on your country).

Once you have your Gerber files, you can order the PCB. Follow the next steps to download the file.

1. Download the Gerber files – click here to download the .zip file

Upload Gerber Files PCB folder

2. Go to PCBWay website and open the PCB Instant Quote page. 

PCBWay Order PCB open instant quote page

3. PCBWay can grab all the PCB details and automatically fill them for you. Use the “Quick-order PCB (Autofill parameters)”.

PCBWay Order PCB autofill parameters

4. Press the “+ Add Gerber file” button to upload the provided Gerber files.

PCBWay Order PCB add gerber file button

And that’s it. You can also use the OnlineGerberViewer to check if your PCB is looking as it should.

PCBWay Upload Gerbers Files and PCB Online preview

If you aren’t in a hurry, you can use the China Post shipping method to lower your cost significantly. In our opinion, we think they overestimate the China Post shipping time.

PCBWay Order PCB China post shipping method

You can increase your PCB order quantity and change the solder mask color. I’ve ordered the Blue color.

PCBWay Order PCB final step and save to cart

Once you’re ready, you can order the PCBs by clicking “Save to Cart” and complete your order.

Unboxing

After approximately one week using the DHL shipping method, I received the PCBs at my office.

PCBWay Unboxing

Everything comes well packed, and the PCBs are really high-quality. The letters on the silkscreen are really well-printed and easy to read. Additionally, the solder sticks easily to the pads.

ESP32-CAM Shield PCB for ESP32-CAM AI Thinker Module Unboxing

Besides the PCBs, I also received some gifts (celebration of their 6th anniversary): a badge, some stickers, a t-shirt, a pen and some rulers.

ESP32-CAM Shield PCBWay Unboxing PCBs and Gift bag

Soldering the Components

The next step is soldering the components to the PCB. You just need to solder female header pins. The PIR motion sensor and the BME280 will then connect to those pins.

Here’s a list of all the components needed to build the PCB shield:

ESP32-CAM AI Thinker Module Shield PCB Parts Components Required

Here’s the soldering tools I’ve used:

TS80 Soldering Iron Review Best Portable Soldering Iron

Read our review about the TS80 Soldering Iron: TS80 Soldering Iron Review – Best Portable Soldering Iron.

The soldering process is pretty simple as you just need to solder the headers pins. There are some exposed GPIOs in the middle of the shield. Solder pins to those GPIOs if you want to use them to connect any other peripherals.

ESP32-CAM AI Thinker Module Shield PCB Soldering Parts Components

Here’s how the ESP32-CAM PCB Shield looks like after assembling.

ESP32-CAM AI Thinker Module Shield PCB Final Assembled Demonstration

Creating a Telegram Bot

The ESP32-CAM will interact with a Telegram bot to receive and handle the messages, and send responses to your Telegram account (sensor readings and photos). Follow the next steps to create a Telegram bot.

Go to Google Play or App Store, download and install Telegram.

Install and Download Telegram

Open Telegram and follow the next steps to create a Telegram Bot. First, search for “botfather” and click the BotFather as shown below. Or open this link t.me/botfather in your smartphone.

botfather

The following window should open and you’ll be prompted to click the start button.

Telegram Start BotFather to Create a new Bot

Type /newbot and follow the instructions to create your bot. Give it a name and username.

Telegram BotFather Create a New Bot

If your bot is successfully created, you’ll receive a message with a link to access the bot and the bot token. Save the bot token because you’ll need it so that the ESP32/ESP8266 can interact with the bot.

Telegram BotFather Get Bot Token

Get Your Telegram User ID

Anyone that knows your bot username can interact with it. To make sure that we ignore messages that are not from our Telegram account (or any authorized users), you can get your Telegram User ID. Then, when your telegram bot receives a message, the ESP can check whether the sender ID corresponds to your User ID and handle the message or ignore it.

In your Telegram account, search for “IDBot” or open this link t.me/myidbot in your smartphone.

Telegram Get Chat ID with IDBot

Start a conversation with that bot and type /getid. You will get a reply back with your user ID. Save that user ID, because you’ll need it later in this tutorial.

Telegram Get Chat ID with IDBot getid

Preparing Arduino IDE

We’ll program the ESP32-CAM using Arduino IDE, so make sure you have the ESP32 add-on installed in your Arduino IDE.

Universal Telegram Bot Library

To interact with the Telegram bot, we’ll use the Universal Telegram Bot Library created by Brian Lough that provides an easy interface for the Telegram Bot API.

Follow the next steps to install the latest release of the library.

  1. Click here to download the Universal Arduino Telegram Bot library.
  2. Go to Sketch Include Library > Add .ZIP Library...
  3. Add the library you’ve just downloaded.

And that’s it. The library is installed.

Important: don’t install the library through the Arduino Library Manager because it might install a deprecated version.

For all the details about the library, take a look at the Universal Arduino Telegram Bot Library GitHub page.

ArduinoJson Library

You also have to install the ArduinoJson library. Follow the next steps to install the library.

  1. Go to Sketch Include Library > Manage Libraries.
  2. Search for “ArduinoJson”.
  3. Install the library.

We’re using ArduinoJson library version 6.15.2.

Install Arduino JSONLibrary

BME280 SparkFun Library

In most of our projects with the BME280 sensor, we use the Adafruit_BME280 library. However, it conflicts with some of the ESP32-CAM libraries. So, to avoid modifying the library files, we used the BME280 Sparkfun library instead that works well with the ESP32-CAM. Follow the next steps to install the BME280 Sparkfun library.

  1. Go to Sketch Include Library > Manage Libraries.
  2. Search for “Sparkfun BME280”.
  3. Install the library.
Install BME280 Sparkfun Library in Arduino IDE

Control ESP32-CAM with Telegram – Arduino Sketch

The following sketch allows you to control the ESP32-CAM using your Telegram account. You’ll also receive a notification with a photo when motion is detected.

Copy the following code to your Arduino IDE. To make it work for you, you need to insert your network credentials (SSID and password), your Telegram Bot Token and your Telegram User ID.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-cam-shield-pcb-telegram/
  
  Project created using Brian Lough's Universal Telegram Bot Library: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot

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

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include "SparkFunBME280.h"

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Use @myidbot to find out the chat ID of an individual or a group
// Also note that you need to click "start" on a bot before it can
// message you
String chatId = "XXXXXXXXXX";

// Initialize Telegram BOT
String BOTtoken = "XXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

bool sendPhoto = false;

WiFiClientSecure clientTCP;

UniversalTelegramBot bot(BOTtoken, clientTCP);

//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

#define FLASH_LED_PIN 4
bool flashState = LOW;

// Motion Sensor
bool motionDetected = false;

// Define I2C Pins for BME280
#define I2C_SDA 14
#define I2C_SCL 15

BME280 bme;
 
int botRequestDelay = 1000;   // mean time between scan messages
long lastTimeBotRan;     // last time messages' scan has been done

void handleNewMessages(int numNewMessages);
String sendPhotoTelegram();

// Get BME280 sensor readings and return them as a String variable
String getReadings(){
  float temperature, humidity;
  temperature = bme.readTempC();
  //temperature = bme.readTempF();
  humidity = bme.readFloatHumidity();
  String message = "Temperature: " + String(temperature) + " ºC \n";
  message += "Humidity: " + String (humidity) + " % \n";
  return message;
}

// Indicates when motion is detected
static void IRAM_ATTR detectsMovement(void * arg){
  //Serial.println("MOTION DETECTED!!!");
  motionDetected = true;
}

void setup(){
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); 
  Serial.begin(115200);
  
  pinMode(FLASH_LED_PIN, OUTPUT);
  digitalWrite(FLASH_LED_PIN, flashState);

  // Init BME280 sensor
  Wire.begin(I2C_SDA, I2C_SCL);
  bme.settings.commInterface = I2C_MODE;
  bme.settings.I2CAddress = 0x76;
  bme.settings.runMode = 3;
  bme.settings.tStandby = 0;
  bme.settings.filter = 0;
  bme.settings.tempOverSample = 1;
  bme.settings.pressOverSample = 1;
  bme.settings.humidOverSample = 1;
  bme.begin();
  
  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_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;

  //init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    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();
  }

  // Drop down frame size for higher initial frame rate
  sensor_t * s = esp_camera_sensor_get();
  s->set_framesize(s, FRAMESIZE_CIF);  // UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA

  // PIR Motion Sensor mode INPUT_PULLUP
  //err = gpio_install_isr_service(0); 
  err = gpio_isr_handler_add(GPIO_NUM_13, &detectsMovement, (void *) 13);  
  if (err != ESP_OK){
    Serial.printf("handler add failed with error 0x%x \r\n", err); 
  }
  err = gpio_set_intr_type(GPIO_NUM_13, GPIO_INTR_POSEDGE);
  if (err != ESP_OK){
    Serial.printf("set intr type failed with error 0x%x \r\n", err);
  }
}

void loop(){
  if (sendPhoto){
    Serial.println("Preparing photo");
    sendPhotoTelegram(); 
    sendPhoto = false; 
  }

  if(motionDetected){
    bot.sendMessage(chatId, "Motion detected!!", "");
    Serial.println("Motion Detected");
    sendPhotoTelegram();
    motionDetected = false;
  }
  
  if (millis() > lastTimeBotRan + botRequestDelay){
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    while (numNewMessages){
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
    lastTimeBotRan = millis();
  }
}

String sendPhotoTelegram(){
  const char* myDomain = "api.telegram.org";
  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();
    return "Camera capture failed";
  }  
  
  Serial.println("Connect to " + String(myDomain));

  if (clientTCP.connect(myDomain, 443)) {
    Serial.println("Connection successful");
    
    String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"chat_id\"; \r\n\r\n" + chatId + "\r\n--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
    String tail = "\r\n--RandomNerdTutorials--\r\n";

    uint16_t imageLen = fb->len;
    uint16_t extraLen = head.length() + tail.length();
    uint16_t totalLen = imageLen + extraLen;
  
    clientTCP.println("POST /bot"+BOTtoken+"/sendPhoto HTTP/1.1");
    clientTCP.println("Host: " + String(myDomain));
    clientTCP.println("Content-Length: " + String(totalLen));
    clientTCP.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
    clientTCP.println();
    clientTCP.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) {
        clientTCP.write(fbBuf, 1024);
        fbBuf += 1024;
      }
      else if (fbLen%1024>0) {
        size_t remainder = fbLen%1024;
        clientTCP.write(fbBuf, remainder);
      }
    }  
    
    clientTCP.print(tail);
    
    esp_camera_fb_return(fb);
    
    int waitTime = 10000;   // timeout 10 seconds
    long startTimer = millis();
    boolean state = false;
    
    while ((startTimer + waitTime) > millis()){
      Serial.print(".");
      delay(100);      
      while (clientTCP.available()){
          char c = clientTCP.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;
    }
    clientTCP.stop();
    Serial.println(getBody);
  }
  else {
    getBody="Connected to api.telegram.org failed.";
    Serial.println("Connected to api.telegram.org failed.");
  }
  return getBody;
}

void handleNewMessages(int numNewMessages){
  Serial.print("Handle New Messages: ");
  Serial.println(numNewMessages);

  for (int i = 0; i < numNewMessages; i++){
    // Chat id of the requester
    String chat_id = String(bot.messages[i].chat_id);
    if (chat_id != chatId){
      bot.sendMessage(chat_id, "Unauthorized user", "");
      continue;
    }
    
    // Print the received message
    String text = bot.messages[i].text;
    Serial.println(text);

    String fromName = bot.messages[i].from_name;

    if (text == "/flash") {
      flashState = !flashState;
      digitalWrite(FLASH_LED_PIN, flashState);
    }
    if (text == "/photo") {
      sendPhoto = true;
      Serial.println("New photo  request");
    }
    if (text == "/readings"){
      String readings = getReadings();
      bot.sendMessage(chatId, readings, "");
    }
    if (text == "/start"){
      String welcome = "Welcome to the ESP32-CAM Telegram bot.\n";
      welcome += "/photo : takes a new photo\n";
      welcome += "/flash : toggle flash LED\n";
      welcome += "/readings : request sensor readings\n\n";
      welcome += "You'll receive a photo whenever motion is detected.\n";
      bot.sendMessage(chatId, welcome, "Markdown");
    }
  }
}

View raw code

How the Code Works

Continue reading to learn how the code works, or skip to the next section.

Importing Libraries

Start by importing the required libraries.

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include "SparkFunBME280.h"

Network Credentials

Insert your network credentials in the following variables.

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

Telegram User ID

Insert your Telegram chat ID on the chatId variable. The one you’ve got from the IDBot.

String chatId = "XXXXXXXXXX";

Telegram Bot Token

Insert your Telegram Bot token you’ve got from Botfather on the BOTtoken variable.

String BOTtoken = "XXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

The sendPhoto Boolean variable indicates whether it is time to send a new photo to your telegram account. By default, it is set to false.

bool sendPhoto = false;

Create a new WiFi client with WiFiClientSecure.

WiFiClientSecure clientTCP;

Create a bot with the token and client defined earlier.

UniversalTelegramBot bot(BOTtoken, clientTCP);

Camera Pins

Define the pins used by the ESP32-CAM:

//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

This is the pin definition for the AI-Thinker board, if you’re using another camera model, check the pinout for your board: ESP32-CAM Camera Boards: Pin and GPIOs Assignment Guide.

Flash LED

Create a variable to hold the flash LED pin (FLASH_LED_PIN). In the ESP32-CAM AI‑Thinker, the flash is connected to GPIO 4. By default, set it to LOW.

#define FLASH_LED_PIN 4
bool flashState = LOW;

Motion Sensor

The motionDetected variable indicates whether motion has been detected. It is set to false by default.

bool motionDetected = false;

BME280

Define the SDA and SCL pins to be used with the BME280.

#define I2C_SDA 14
#define I2C_SCL 15

Create a BME280 instance called bme.

BME280 bme;

Request Delay

The botRequestDelay and lasTimeBotRan variables are used to check for new Telegram messages every x number of seconds. In this case, the code will check for new messages every second (1000 milliseconds). You can change that delay time in the botRequestDelay variable.

int botRequestDelay = 1000;   // mean time between scan messages
long lastTimeBotRan;     // last time messages' scan has been done

handleNewMessages()

The handleNewMessages() function handles what happens when new messages arrive.

void handleNewMessages(int numNewMessages){
  Serial.print("Handle New Messages: ");
  Serial.println(numNewMessages);

Get the chat ID for that particular message and store it in the chat_id variable. The chat ID identifies who sent the message.

String chat_id = String(bot.messages[i].chat_id);

If the chat_id is different from your chat ID (chatId), it means that someone (that is not you) has sent a message to your bot. If that’s the case, ignore the message and wait for the next message.

if (chat_id != chatId){
  bot.sendMessage(chat_id, "Unauthorized user", "");
  continue;
}

Otherwise, it means that the message was sent from a valid user, so we’ll save it in the text variable and check its content.

String text = bot.messages[i].text;
Serial.println(text);

The from_name variable saves the name of the sender.

String fromName = bot.messages[i].from_name;

If it receives the /flash message, invert the flashState variable and update the flash led state. If it was previously LOW, set it to HIGH. If it was previously HIGH, set it to LOW.

if (text == "/flash") {
  flashState = !flashState;
  digitalWrite(FLASH_LED_PIN, flashState);
}

If it receives the /photo message, set the sendPhoto variable to true. Then, in the loop(), we’ll check the value of the sendPhoto variable and proceed accordingly.

if (text == "/photo") {
  sendPhoto = true;
  Serial.println("New photo request");
}

If it receives the /readings message, call the getReadings() function (we’ll take a look at that function later on) and send the readings to the bot.

if (text == "/readings"){
  String readings = getReadings();
  bot.sendMessage(chatId, readings, "");
}

Sending a message to the bot is very simple. You just need to use the sendMessage() method on the bot object and pass as arguments the recipient’s chat ID, the message, and the parse mode.

bool sendMessage(String chat_id, String text, String parse_mode = "")

Finally, if it receives the /start message, we’ll send the valid commands to control the ESP. This is useful if you happen to forget what are the commands to control your board.

if (text == "/start"){
  String welcome = "Welcome to the ESP32-CAM Telegram bot.\n";
  welcome += "/photo : takes a new photo\n";
  welcome += "/flash : toggle flash LED\n";
  welcome += "/readings : request sensor readings\n\n";
  welcome += "You'll receive a photo whenever motion is detected.\n";
  bot.sendMessage(chatId, welcome, "Markdown");
}

sendPhotoTelegram()

The sendPhotoTelegram() function takes a photo with the ESP32-CAM.

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

Then, it makes an HTTP POST request to send the photo to your telegram bot.

clientTCP.println("POST /bot"+BOTtoken+"/sendPhoto HTTP/1.1");
clientTCP.println("Host: " + String(myDomain));
clientTCP.println("Content-Length: " + String(totalLen));
clientTCP.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
clientTCP.println();
clientTCP.print(head);

getReadings()

The getReadings() function requests temperature and humidity from the BME280 sensor.

String getReadings(){
  float temperature, humidity;
  temperature = bme.readTempC();
  //temperature = bme.readTempF();
  humidity = bme.readFloatHumidity();

The readings are concatenated in the message variable that is returned by the function.

String message = "Temperature: " + String(temperature) + " ºC \n";
message += "Humidity: " + String (humidity) + " % \n";
return message;

detectsMovement()

The detectsMovement() is a callback function that is called when motion is detected. In this case, we set the motionDetected variable to true. Then, in the loop(), we’ll handle what happens when there’s motion (sends a photo).

static void IRAM_ATTR detectsMovement(void * arg){
  //Serial.println("MOTION DETECTED!!!");
  motionDetected = true;
}

setup()

In the setup(), initialize the Serial Monitor.

Serial.begin(115200);

Set the flash LED as an output and set it to its initial state.

pinMode(FLASH_LED_PIN, OUTPUT);
digitalWrite(FLASH_LED_PIN, flashState);

Initialize the BME280 sensor:

// Init BME280 sensor
Wire.begin(I2C_SDA, I2C_SCL);
bme.settings.commInterface = I2C_MODE;
bme.settings.I2CAddress = 0x76;
bme.settings.runMode = 3;
bme.settings.tStandby = 0;
bme.settings.filter = 0;
bme.settings.tempOverSample = 1;
bme.settings.pressOverSample = 1;
bme.settings.humidOverSample = 1;
bme.begin();

Connect your ESP32-CAM to your local network.

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());

Configure and initialize the camera.

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;

//init with high specs to pre-allocate larger buffers
if(psramFound()){
  config.frame_size = FRAMESIZE_UXGA;
  config.jpeg_quality = 10;  //0-63 lower number means higher quality
  config.fb_count = 2;
} else {
  config.frame_size = FRAMESIZE_SVGA;
  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();
}

// Drop down frame size for higher initial frame rate
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_CIF);  // UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA

Setup an interrupt on GPIO 13:

err = gpio_isr_handler_add(GPIO_NUM_13, &detectsMovement, (void *) 13);
if (err != ESP_OK){
  Serial.printf("handler add failed with error 0x%x \r\n", err); 
}
err = gpio_set_intr_type(GPIO_NUM_13, GPIO_INTR_POSEDGE);
if (err != ESP_OK){
  Serial.printf("set intr type failed with error 0x%x \r\n", err);
}

loop()

In the loop(), check the state of the sendPhoto variable. If it is true, call the sendPhotoTelegram() function to take and send a photo to your telegram account.

if (sendPhoto){
  Serial.println("Preparing photo");
  sendPhotoTelegram(); 
  sendPhoto = false; 
}

When it’s done, set the sendPhoto variable to false.

sendPhoto = false; 

When motion is detected, send a notification to your Telegram account and call the senPhototoTelegram() function. Then, set the motionDetected variable to false.

if(motionDetected){
  bot.sendMessage(chatId, "Motion detected!!", "");
  Serial.println("Motion Detected");
  sendPhotoTelegram();
  motionDetected = false;
}

Check for new Telegram messages every second.

if (millis() > lastTimeBotRan + botRequestDelay){
  int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
  while (numNewMessages){
    Serial.println("got response");
    handleNewMessages(numNewMessages);
    numNewMessages = bot.getUpdates(bot.last_message_received + 1);
  }
  lastTimeBotRan = millis();
}

When a new message arrives, call the handleNewMessages() function.

while (numNewMessages){
  Serial.println("got response");
  handleNewMessages(numNewMessages);
  numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}

That’s pretty much how the code works.

Upload Code to the ESP32-CAM

After making the necessary changes, upload the code to your ESP32-CAM (before connecting the shield). Follow the next steps to upload code or follow this tutorial: How to upload code to ESP32-CAM.

1) Wire the ESP32-CAM to the FTDI programmer as shown in the following diagram.

Note: the order of the FTDI pins on the diagram may not match yours. Make sure you check the silkscreen label next to each pin.

Important: GPIO 0 needs to be connected to GND so that you’re able to upload code.

2) Go to Tools Board and select AI-Thinker ESP32-CAM. You must have the ESP32 add-on installed. Otherwise, this board won’t show up on the Boards menu.

3) Go to Tools Port and select the COM port the ESP32-CAM is connected to.

4) Then, click the Upload button in your Arduino IDE.

Program ESP32-CAM with Arduino IDE

5) When you start to see some dots on the debugging window, press the ESP32-CAM on-board RST button.

Upload code to ESP32-CAM Connecting to Serial Port
ESP32-CAM Press RESET RST on-board button to restart

After a few seconds, the code should be successfully uploaded to your board.

6) When you see the “Done uploading” message, remove GPIO 0 from GND.

Open the Serial Monitor, press the on-board RST button, and check that the ESP32-CAM is connecting to your network without any problems.

Demonstration

With the code uploaded to your ESP32-CAM, attach the PCB shield and all the components.

ESP32-CAM Shield PCB Stack to AI Thinker Module

Apply power using the 5V and GND pins on the shield.

Then, press the ESP32-CAM RST button, so that it starts running the code.

Now, open your Telegram account and test your board. Send the following messages to your ESP32 Telegram bot to control your ESP32-CAM:

  • /start: sends a welcome message with the valid commands to control the shield;
  • /flash: toggles the ESP32-CAM LED Flash;
  • /photo: takes a new photo and sends it to your Telegram account;
  • /readings: requests the latest BME280 sensor readings.

Additionally, you’ll receive a notification with a photo whenever motion is detected.

Control ESP32-CAM with Telegram Take Photos Control Outputs Request Sensor Readings and Motion Notifications Demonstration

If you try to interact with your bot from another account, you’ll get the the “Unauthorized user” message.

Control ESP32 ESP8266 Outputs Telegram Unauthorized user

Wrapping Up

In this tutorial we’ve created a PCB shield for the ESP32-CAM with a PIR motion sensor and BME280. This creates a more permanent circuit in a small footprint that you can put inside a small enclosure or dummy camera.

ESP32-CAM shield PCB Demonstration Fake dummy surveillance camera

You also learned how to use your Telegram account to control your ESP32-CAM using a Telegram bot. This allows you to control and monitor your board from anywhere, as long as you have internet access in your smartphone.

You can also create your own code to do any other tasks with the shield.

We have other similar projects that include building and designing PCBs that you may like:

Learn more about the ESP32-CAM with our resources:

We’re giving away 5 bare PCBs to someone that posts a comment below (comments might take up to 24 hours to be approved)! Simply post a comment in this blog post about what you would like to do with the PCB and you’re entered for a chance to win one of these bare PCBs. We’re currently confirm the winners and we will announce them during this weekend (August 22). So, stay tuned! [Update] the giveaway ended and the winners are: Gerald Maurer, Jason Wilkins, Svein Utne, Domenico Carvetta, and João Paulo.



Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »

Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our weekly newsletter!

59 thoughts on “ESP32-CAM with Telegram: Take Photos, Control Outputs, Request Sensor Readings and Motion Notifications”

  1. This tutorial offers a clear insight in the whole process off processing and forwarding data. So I sure will to analyse also this example. One thing that thrills me with this example: how can I adapt the software, so that it can run on batteries. Maybe by using deepsleep and build some low current circuit that awakes the software of the ESP32. Maybe by using an attiny85 that itself wakes up every 10 seconds and then very shortly tests movement.

    Reply
  2. Great looking project, if I had the PCB I would modify it to control a servo. As is, the code could be altered to include a deep sleep routine allowing extended battery life. I’m going to have a go at making this and modifying the software myself!

    Reply
  3. Dear Sara,
    why don’t use directly the instruction: uint32_t instead of uint16_t to cover the UXGA format? Am I wrong ?

    Thanks. Domenico

    Reply
  4. Molto interessante come progetto. Mi piacerebbe usarlo per assemblare, anche con l’aiuto di una stampante 3d, la mia prima ipCam completamente programmabile. Mi piacerebbe anche poter sfruttare i restanti PIN rimasti liberi per poter eccitare eventualmente dei relay all’occorrenza. Grazie a voi per questo tutorial.

    Very interesting as a project. I would like to use it to assemble, even with the help of a 3d printer, my first fully programmable ipCam. I would also like to be able to take advantage of the remaining PINs left free to eventually excite relays if necessary. Thanks to you for this tutorial.

    Reply
  5. I really appreciate the whole process including PCB. Been researching this as a part of other projects. So glad to see this included here! Kudos to you.

    Reply
  6. There are a few things wrong with this sketch.
    First off it’s missing the declaration of the clientTCP variable (WiFiClientSecure clientTCP;).
    Then there are these extraneous chatId variables (I replaced them with CHAT_ID).
    Finally you need to add String casts around CHAT_ID and BOTtoken wherever they are used.

    Once all that is done it compiles and works.

    And to Domenico’s point, for low res camera captures 16bit is OK but I changed the code to 32 bit so I can set my camera to a higher resolution.

    Reply
    • Hello Steve, thank you so much for testing our code and letting me know. While removing the crendetials, we’ve copied the wrong bot token and chat id definitions. We’ve also deleted the WiFiClientSecure declaration by mistake (while explaining how the code works).
      All those changes have been made and the code now compiles.

      Thanks again!

      Reply
  7. Thanks for this excellent tutorial (as all your tutorials, very clear and interesting).
    I would very much like to have this custom made PCB Shield to try an adaption of this wonderful project as a remote ringbell image notification (i’ll leave the suggestion here).
    The idea would be to use a dummy camera like in your suggestion, but instead of having a motion sensor, it would have an input from the main doorbell button, and an output for the conventional doorbell system, while allowing the Telegram Bot to transmit the photo of the person @ the door, taken the moment it presses the doorbell button 🙂
    What do you think about that? (maybe an idea for your next tutorial?)

    Reply
  8. Hey, this is so great, I am going to try that. But would it be possible to try the very same thing on cloudmqtt? Especially the camera picture to be posted over cloudmqtt?
    Thanks in advance 🙂

    Reply
  9. Translation courtesy of Google
    I have read several times correctly interpret the indications that this web https://arduinojson.org/v6/doc/upgrade/
    but I have to admit that, after several failed attempts,
    The solution of updating Brian Lough’s UniversalTelegramBot.cpp library version 1.1.0 (installed) to adapt it to version 6.x of ArduinoJson is beyond my possibilities. Sorry

    I would appreciate a copy of the UniversalTelegramBot.cpp file from whoever obtained it, or the indications of the commands that I must modify.

    Reply
  10. Translation courtesy of Google
    I got it !!, after much struggle, I have managed to get UniversalTelegramBot to understand with ArduinoJson V6.16.1. (Installed)
    I no longer have compilation errors. Thank you all !!

    Reply
  11. Dear Sara, about the PIR Motion Sensor mode INPUT_PULLUP, I found that sometime you use as follows:
    err = gpio_isr_handler_add(GPIO_NUM_13, &detectsMovement, (void *) 13);

    sometime also:
    esp_err_t err = gpio_isr_handler_add(GPIO_NUM_13, &detectsMovement, (void *) 13);

    I guess both works fine, but unknown the difference, thanks for letting us know.

    Reply
  12. Very good project.
    I have been waiting for something like this for several years, but now I got it.
    Today I put one ESP32-Cam in my sailboat, with an old phone that is providing the internet connection with an extra data sim card. This cost less than €3 per month. Now I plan to also put one or two in my cottage. I might want to use two at home two in the sailboat and two at the cottage.
    Then the question is: what do I need to change? The chatId or the BOTtoken or both?

    Reply
    • Yes, just be sure to change the text on the “bot.sendMessage” line of code on each ESP32-CAM so you can identify which sensor is sending the message!!!

      So, instead of “Motion detected!!”, you should put “Home entry Motion detected!!”, “Sailboat entry Motion detected!!” or whatever makes you identify the origin of motion 🙂

      Reply
      • Thanks a lot for this help. What if I want to send a message to one of the ESP32-CAM, then maybe I need different chatId for each?

        Reply
  13. Great project. I put it together and got it running with minimal effort. Your instructions were excellent.
    I added two commands; moff and mon – which disable and enable the checking of the motion sensor. I did this by adding a variable;
    bool motionDetectEnable = false;
    and modifying the check of motionDetected as follows;
    if(motionDetected && motionDetectEnable) {

    And of course adding code to process the commands;
    if (text == “/mon”) {
    motionDetectEnable = true;
    Serial.println(“New motion detect ON request”);
    }
    if (text == “/moff”) {
    motionDetectEnable = false;
    Serial.println(“New motion detect OFF request”);
    }

    I did this because I seem to get an abundance of motionDetected even when in a quiet room.
    I’ve also noticed that it often takes minutes to receive the commands. Have others encountered this?

    Thanks again for your excellent instructions!

    Reply
  14. Hola te saludo desde Colombia, buscando en Internet sobre IOT te encontré, es asombroso el trabajo que haces, te felicito y agradezco en nombre propio y de la comunidad el tiempo que debes dedicarle a esto. Muchas gracias y fuerza para seguir en la labor.

    Reply
  15. Dear Rui & Sara,

    thanks for another great project. I’m signed up to your RNTLAB for a few years now to support the work you do.

    I would like to move from using breadboards to PCB’s like you have in this one.

    I started using KiCad to draw my circuits but am struggling to then create the PCB.

    I have just loaded EasyEDA and it seems much more user friendly.

    One problem I am struggling with is that i want to use a different ESP kit

    I want to use ESP_Devkitc_v4 when i try and find that device for the footprint and to use in the circuit i cant find it. I also cannot find the one you have actually used, if i search for ESP32_DOIT_DEVKIT_V1_36_SHIELD that also is not listed.

    I am obliviously missing something, would you be so kind as to advise how you would select a device that matches the device you are using in the circuit and also how you select for the correct footprint on the PCB layout.

    Greatly appreciate your assistance
    Jase

    Reply
    • Hello Jason, Try to just search “ESP32”, then look for all the components and try to find the right footprint. If you type the exact board name in the search bar, you might not find it… I hope that helps!

      Reply
      • Many thanks,

        When I first searched for ESP32 after install only found about three. The next day after giving up I rebooted and then the same search term “ESP32” shows loads up and mine was listed.

        Really strange

        Many thanks

        Reply
  16. I run into an other problem. The HC-SR501 got a potmeter for adjusting the sensetivity, but from max to min there is very small change, so when the vind is blowing and the boat is moving, it starts to take pictures all the time even on the lowest sensetivity, so after about 20 pictures Telegram stop working for 3 hours.

    Reply
    • For a boat a movement sensor is probably not the best option. What are you trying to detect? If it’s someone on board you may want to use a pressure mat instead.

      Reply
  17. I do not have any pressure mat, but I got some RLWL-0516. When you put in a 1M ohm resistor its sensitivity changes from 9 meters till only 4 meters. I will try that tomorrow.

    Reply
  18. It looks like the RLWL-0516 will work, when I put it in a can, and let the opening point in the direction I want to take the picture when motion. The RLWL-0516 uses radar tecnology, and it works 360 degrees even true table tops and the hull of the boat, but with a metal can, it can be stoped. The problem now is that I took too many pictures during this testing, so now I am banned again from Telegram for some hours, so I cannot make the final test before tomorrow. What is the rule Telegram is following when banning somone?

    Reply
  19. hello, I tried to load the program but after compilation the esp can’t connect to the home network. I am sure I have entered the correct password and ssid because I have copied and pasted them from another program that work. can you tell me how to solve this problem?

    Reply
  20. Today I received some AM312 PIR. Thay are small and has only 3 meter range, but that was just what I needed, so now it looks to be working fine. We will know more in a day or two.

    Reply
  21. Useful project. Thanks for all the work you put into it. I built it and it works, it works too well, in that it constantly triggers the motion detector and sends me pictures…
    Any suggestions as to why it is so sensitive and what to do about it?

    Thanks,
    Jacob

    Reply
  22. Try using the AM312, og is lese sensitiv. Ny problem now is that Telegram stop working after some hours, and I have to test the ESP32 to make it tun again.

    Reply
  23. Thanks for the project, it’s great, I’ve already ordered some boards.
    2 questions about compatibility:

    1.- use the RCWL-0516 presence sensor to replace the AM312 (it works inside the fake camera)

    2.- use the DHT11 sensor to replace the BME280. (I have several )

    It’s just out of curiosity

    Reply
  24. Hi Rui and Sara, sadly my comment from yesterday disappeard. Was it deleted? I tried the project but unfortunatly the bot.getUpdates() always returns 0 even though there are new messages for the bot in the chat.
    I am sure the telegram bot integration works bebause I can post messages via bot.sendMessage(). So the Bot API-key, the chat_ID and my WiFi credentials are crearly okay.
    Do you have any idea how to solve this issue? The issue looks similar to this one: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot/issues/121. However on ESP32 there is no more WifiClientSecure.setInsecure() method as suggested there.
    Any help is much appreciated.

    Reply
    • Hi.
      I can’t find any previous comment from you.
      The Telegram examples always worked fine for us with both the ESP32 and ESP8266 without any issues.
      The link you’ve sent me is related with the ESP8266.
      I don’t know how to solve the issue for the ESP32.
      I see that you’ve opened an issue on their forum.
      If you find out something, please share. Other people might be having the same issue.
      Regards,
      Sara

      Reply
  25. Thank you guys very much for this project. It is very nicely presented and documented. I built it and it works well first time. Now, I added a small change whereby I can enable/disable the motion detector via an additional command –
    /trigg_en. That works fine however for some reason the /start command stopped working. I expected to see the “menu” every time I hit /start, but it stopped after the first time. Any ideas? I then noticed that removing the “Markdown” from bot.sendMessage(chatId, welcome, “Markdown”); fixed the problem. Any ideas?

    Reply
  26. Hey. Do I have to make my own ibot for each camera? or two respond to different calls for example / photo for cam 1 and / photo wp for second cam.
    Another problem is that both cam’s do not always start up when turning on, then I have to reset via the button too often. Often the cam cannot be called up, even at a short distance, and only works again after a reset or on / off of the power supply.
    How much power / amp the cam actually uses. That is not clear to me.
    Nice project that I enjoy working on.

    Reply
  27. Hello great tutorial

    i just have one little problem
    I have a pressure mat instead of the presence sensor. I connected this with a 10k PULLUP resistor.
    My problem is that I keep getting motion detections.
    am I doing something wrong?
    best regards
    Gerhard

    Reply
  28. Quote “If you try to interact with your bot from another account, you’ll get the the “Unauthorized user” message.”

    I do not want this feature, since i want all of the people living in a house to receive Photo
    how can i remove this authorization? or add multiple accounts to ‘authorized’ list?

    Reply
    • Hi.
      You can use a group for that, where several people inside that group can control and receive messages. We’ll post an article about that soon.

      Alternatively, you can delete the following lines in the code:
      for (int i = 0; i < numNewMessages; i++){
      // Chat id of the requester
      String chat_id = String(bot.messages[i].chat_id);
      if (chat_id != chatId){
      bot.sendMessage(chat_id, “Unauthorized user”, “”);
      continue;
      }

      Or you can add all authorized chat IDs and check inside that if statement if it corresponds to one of the authorized IDs.

      I hope this helps.
      Regards,
      Sara

      Reply
      • Hey Sara,

        Yes i was able to figure it out,
        I tried using Group but it was difficult to get a chat_id for a group, the ID bot doesnt tell me, i was unable to get the chat id of a group.

        so i just addid another statement chat_id = chatId ; and itll assign the unknown ID to current id

        Reply
  29. Hey. Thank you for the article. Putting together the project – everything works fine. I don’t understand only one thing – why the camera settings are made
    config.frame_size = FRAMESIZE_UXGA;
    or
    config.frame_size = FRAMESIZE_SVGA;
    and the photos come from the bot with a resolution of only
    FRAMESIZE_CIF, // 400×296
    How can I fix this?
    Sorry for my English. This is google translation ..

    Reply
  30. Hallo Sara, Rui,
    Please help me out . . .
    What address should I use to access my ESP32-Cam ?
    When I enter /start nothing happens !
    Am I missing something ?
    Regards,
    Met vriendelijke groeten,
    Tom

    Reply
    • Hi.
      What do you mean?
      With this project, you control the ESP32-CAM from your Telegram account. It is not accessible from a browser.
      Regards,
      Sara

      Reply
  31. Hi!

    Thank you for the great content!

    I followed the schematics on a breadboard and the first thing I tried to do was to run the i2c scanner in order to find the address for BME sensor but I keep getting “No I2C devices found”. I was expecting the actual address.
    Am I missing something? Is it normal? Are GPIO14 (SDA) and GPIO15(SCL) the actual I2C pins? I tried with different I2C devices but got the same result.
    I’ve got pictures from my setup, but can’t upload them =)

    Thanks in advance!

    João

    Reply
    • Hi.
      Those are not the default ESP32 I2C pins, but we set them on the code.
      If you’re running an I2C scanner sketch without specifying those pins, it won’t find any sensor, because it will look up on the default pins.
      Usually, the I2C address of the BME280 sensor is 0x76.
      I hope this makes sense.
      Regards,
      Sara

      Reply
  32. Hello, I have this error in the compilation, so I understand the library in the IDE is missing. But I didn’t find it on the internet. Could you guide me?
    Arduino: 1.8.12 (Windows 7), Placa:”AI Thinker ESP32-CAM”

    Foram encontradas múltiplas bibliotecas para “WiFi.h”
    esp32-cam-shield-telegram:13:23: fatal error: soc / soc.h: No such file or directory

    Usado: C:\Users\Thalis Mazzarino\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\libraries\WiFi
    compilation terminated.

    Não usado: C:\Program Files (x86)\Arduino\libraries\WiFi
    exit status 1
    soc / soc.h: No such file or directory

    Reply

Leave a Comment

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.