ESP32-CAM-Based Real-Time Face Detection and Counting System

Hello friends. We hope you are doing fine. Today we are back with another interesting project. It is based on the image processing technology. Developing efficient and cost-effective solutions for real-time applications is becoming increasingly important in the area of embedded systems and computer vision. This project makes full use of ESP32-CAM. ESP32-CAM is a compact and AI-enabled microcontroller with built-in Wi-Fi capabilities. We will create a real-time face detection and counting system.

The ESP32-CAM serves as the core of the system. It captures high-resolution images at 800x600 resolution and hosts an HTTP server to serve individual JPEG images over a local network. The device’s efficient JPEG compression and network capabilities ensure minimal latency while maintaining high-quality image delivery, enabling real-time processing on the client side.

On the client side, a Python application powered by OpenCV collects image frames from the ESP32-CAM. Using Haar cascade classifiers, the application detects faces in each frame. It can also figure out whether they are frontal or in profile orientation.

This project is focused on face detection and counting. It marks detected faces with bounding boxes. It also counts both frontal and profile faces seen in the video stream.

Applications of this face detection and counting system include smart attendance systems, people flow monitoring in public spaces, and automation solutions in retail or event management. This project demonstrates how IoT-enabled devices like the ESP32-CAM can work seamlessly with computer vision algorithms to provide cost-effective and reliable solutions for real-world challenges. By focusing solely on face detection and counting, the system achieves an optimal balance between simplicity, scalability, and computational efficiency.

System Architecture of Face Counting with ESP32-CAM and Python

1. Hardware Layer:

  • ESP32-CAM:

    • Captures images at a resolution of 800x600 (or specified resolution).

    • Serves captured images over an HTTP server at a specific endpoint (e.g., /cam-hi.jpg).

    • Configured to operate as an access point or station mode connected to Wi-Fi.

  • Network Connection:

    • Wi-Fi provides communication between the ESP32-CAM and the Python application running on a computer.

  • Computer:

    • Runs the Python application to process the images and display results.

2. Software Layer:

  • ESP32-CAM Firmware:

    • Configures the camera for capturing images.

    • Sets up a lightweight HTTP server to serve JPEG images to connected clients.

  • Python Application:

    • Fetches images from the ESP32-CAM.

    • Processes images to count and annotate detected faces.

3. Communication Layer:

  • HTTP Protocol:

    • The ESP32-CAM serves images using HTTP.

    • The Python application uses HTTP GET requests to fetch the images from the camera.

4. Face Detection and Processing Layer:

  • Image Acquisition:

    • Python fetches images from the ESP32-CAM endpoint.

  • Preprocessing:

    • Converts the fetched image to a format suitable for OpenCV operations (e.g., cv2.imdecode to convert byte data into an image).

  • Face Detection:

    • Uses OpenCV's Haar Cascade classifiers to detect:

      • Frontal Faces: Uses haarcascade_frontalface_default.xml.

      • Profile Faces: Uses haarcascade_profileface.xml.

    • Counts the number of faces detected in the current frame.

  • Annotation:

    • Draws bounding boxes (rectangles) and labels around detected faces on the image frame.

    • Adds text overlays to display the count of detected frontal and profile faces.

5. User Interface Layer:

  • Visual Output:

    • Displays the annotated frames with bounding boxes and face counts in a real-time OpenCV window titled "Face Detector."

  • User Interaction:

    • Allows the user to terminate the application by pressing the 'q' key.

6. Workflow Summary:

  1. Image Capture:

    • ESP32-CAM captures and serves the image.

  2. Image Fetching:

    • Python retrieves the image via an HTTP GET request.

  3. Processing and Detection:

    • Haar Cascade classifiers detect faces, count them, and annotate the frame.

  4. Display and Output:

    • Python displays the processed image in a GUI window with visual feedback for face counts.

  5. Loop and Termination:

    • The loop continues until the user exits.

List of components

Components

Quantity

ESP32-CAM WiFi + Bluetooth Camera Module

1

FTDI USB to Serial Converter 3V3-5V

1

Male-to-female jumper wires

4

Female-to-female jumper wire

1

MicroUSB data cable

1

Circuit diagram

The following is the circuit diagram for this project.

Fig: Circuit diagram

ESP32-CAM WiFi + Bluetooth Camera Module

FTDI USB to Serial Converter 3V3-5V (Voltage selection button should be in 5V position)

5V

VCC

GND

GND

UOT

Rx

UOR

TX

IO0

GND (FTDI or ESP32-CAM)

Programming

Board installation

If it is your first project with any board of the ESP32 series, you need to do the board installation first. If ESP32 boards are already installed in your Arduino IDE, you can skip this installation section. You may also need to install the CP210x USB driver.

  • Go to File > preferences, type https://dl.espressif.com/dl/package_esp32_index.json and click OK. 

Fig: Board Installation

  • Go to Tools>Board>Boards Manager and install the ESP32 boards. 

Fig: Board Installation

Install the ESP32-CAM library.

  • Download the ESP32-CAM library from Github (the link is given in the reference section). Then install it by following the path sketch>include library> add.zip library. 

Now select the correct path to the library, click on the library folder and press open. 

Board selection and code uploading.

Connect the camera board to your computer. Some camera boards come with a micro USB connector of their own. You can connect the camera to the computer by using a micro USB data cable. If the board has no connector, you have to connect the FTDI module to the computer with the data cable. If you never used the FTDI board on your computer, you will need to install the FTDI driver first.

  • After connecting the camera,  Go to Tools>boards>esp32>Ai thinker ESP32-CAM

Fig: Camera board selection

After selecting the board, select the appropriate COM port and upload the following code:

#include

#include

#include

 

const char* WIFI_SSID = "Hamad";

const char* WIFI_PASS = "barsha123";

 

WebServer server(80);

 


static auto hiRes = esp32cam::Resolution::find(800, 600);

void serveJpg()

{

  auto frame = esp32cam::capture();

  if (frame == nullptr) {

    Serial.println("CAPTURE FAIL");

    server.send(503, "", "");

    return;

  }

  Serial.printf("CAPTURE OK %dx%d %db\n", frame->getWidth(), frame->getHeight(),

                static_cast(frame->size()));

 

  server.setContentLength(frame->size());

  server.send(200, "image/jpeg");

  WiFiClient client = server.client();

  frame->writeTo(client);

}

 


 

void handleJpgHi()

{

  if (!esp32cam::Camera.changeResolution(hiRes)) {

    Serial.println("SET-HI-RES FAIL");

  }

  serveJpg();

}

 


 

 

void  setup(){

  Serial.begin(115200);

  Serial.println();

  {

    using namespace esp32cam;

    Config cfg;

    cfg.setPins(pins::AiThinker);

    cfg.setResolution(hiRes);

    cfg.setBufferCount(2);

    cfg.setJpeg(80);

 

    bool ok = Camera.begin(cfg);

    Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");

  }

  WiFi.persistent(false);

  WiFi.mode(WIFI_STA);

  WiFi.begin(WIFI_SSID, WIFI_PASS);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

  }

  Serial.print("http://");

  Serial.println(WiFi.localIP());


  Serial.println("  /cam-hi.jpg");


 

 

  server.on("/cam-hi.jpg", handleJpgHi);


 

  server.begin();

}

 

void loop()

{

  server.handleClient();

}



After uploading the code, disconnect the IO0 pin of the camera from GND. Then press the RST pin. The following messages will appear.

Fig: Code successfully uploaded to ESP32-CAM

You have to copy the IP address and paste it into the following part of your Python code. 

Python code

Haar Cascade Models

Face detection in this project relies on pre-trained Haar cascade models provided by OpenCV. These models are essential for detecting features like frontal and profile faces in images. Haar cascades are XML files containing trained data for specific object detection tasks. For this project, the following models are used:

  1. Frontal Face Detection Model: haarcascade_frontalface_default.xml

  2. Profile Face Detection Model: haarcascade_profileface.xml

These files are mandatory for the Python code to perform face detection. Below is a guide on how to download and set up these files.


Step 1: Downloading the Models

The Haar cascade models can be downloaded directly from OpenCV’s GitHub repository.

  1. Open your web browser and go to the OpenCV GitHub repository for Haar cascades:
    https://github.com/opencv/opencv/tree/master/data/haarcascades

  2. Locate the following files in the repository:

    • haarcascade_frontalface_default.xml

    • haarcascade_profileface.xml

  3. Click on each file to open its content.

  4. On the file's page, click the Raw button to view the raw XML content.

  5. Right-click and select Save As to download the file. Save it with its original filename (.xml extension) to the directory where your Python script (main.py) is saved.


Step 2: Placing the Files

Since the XML files are placed in the same directory as your Python script, there is no need to specify a separate folder in your code. Ensure the downloaded files are saved in the same directory as your script, as shown below:

project_folder/

├── main.py

├── haarcascade_frontalface_default.xml

└── haarcascade_profileface.xml



Step 3: Updating the Python Script

Update your script to load the models from the current directory. This requires referencing the XML files directly without a folder path:

frontal_face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")

profile_face_cascade = cv2.CascadeClassifier("haarcascade_profileface.xml")



Verifying the Setup

  1. Ensure the XML files are saved in the same directory as the Python script.

  2. Run the Python script. If the models load successfully, there will be no errors related to file loading, and face detection should function as expected.

By downloading the files and placing them in the same directory as your script, you simplify the setup and enable seamless face detection functionality.




Main python script 

Copy-paste the following Python code and save it using a Python interpreter. 

import cv2

import requests

import numpy as np


# Replace with your ESP32-CAM's IP address

ESP32_CAM_URL = "http://192.168.1.104/cam-hi.jpg"


# Load Haar Cascades for different types of face detection

frontal_face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")

profile_face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_profileface.xml")


def process_frame(frame):

    # Convert to grayscale for detection

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)


    # Perform frontal face detection

    frontal_faces = frontal_face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(20, 20))


    # Perform profile face detection

    profile_faces = profile_face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(20, 20))


    # Draw rectangles for detected frontal faces

    for (x, y, w, h) in frontal_faces:

        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)  # Red for frontal faces

        cv2.putText(frame, "Frontal Face", (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)


    # Draw rectangles for detected profile faces

    for (x, y, w, h) in profile_faces:

        cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)  # Blue for profile faces

        cv2.putText(frame, "Profile Face", (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)


    # Add detection counts to the frame

    cv2.putText(frame, f"Frontal Faces: {len(frontal_faces)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

    cv2.putText(frame, f"Profile Faces: {len(profile_faces)}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)


    return frame


while True:

    # Fetch an image from the ESP32-CAM

    response = requests.get(ESP32_CAM_URL)

    if response.status_code == 200:

        img_arr = np.asarray(bytearray(response.content), dtype=np.uint8)

        frame = cv2.imdecode(img_arr, cv2.IMREAD_COLOR)


        # Process and display the frame

        processed_frame = process_frame(frame)

        cv2.imshow("Face Detector", processed_frame)


        # Quit when 'q' is pressed

        if cv2.waitKey(1) & 0xFF == ord('q'):

            break

    else:

        print("Failed to fetch image from ESP32-CAM")


cv2.destroyAllWindows()



Setting Up Python Environment

Install Dependencies:

1)Create a virtual environment:
python -m venv venv

source venv/bin/activate  # Linux/Mac

venv\Scripts\activate   # Windows

2)Install required libraries:

pip install opencv-python numpy

After setting the Pythong Environment, run the Python code. 

ESP32-CAM code breakdown

#include

#include

#include


  • #include : Adds support for creating a lightweight HTTP server.

  • #include : Allows the ESP32 to connect to Wi-Fi networks.

  • #include : Provides functions to control the ESP32-CAM module, including camera initialization and capturing images.

 

const char* WIFI_SSID = "SSID";

const char* WIFI_PASS = "password";

 


  • WIFI_SSID and WIFI_PASS: Define the SSID and password of the Wi-Fi network that the ESP32 will connect to.

 WebServer server(80);


  • WebServer server(80): Creates an HTTP server instance that listens on port 80 (default HTTP port).

 


static auto hiRes = esp32cam::Resolution::find(800, 600);


esp32cam::Resolution::find: Defines camera resolutions:

  • hiRes: High resolution (800x600).

void serveJpg()

{

  auto frame = esp32cam::capture();

  if (frame == nullptr) {

    Serial.println("CAPTURE FAIL");

    server.send(503, "", "");

    return;

  }

  Serial.printf("CAPTURE OK %dx%d %db\n", frame->getWidth(), frame->getHeight(),

                static_cast(frame->size()));

 

  server.setContentLength(frame->size());

  server.send(200, "image/jpeg");

  WiFiClient client = server.client();

  frame->writeTo(client);

}

 

 


  • esp32cam::capture: Captures a frame from the camera.

  • Failure Handling: If no frame is captured, it logs a failure and sends a 503 error response.

  • Logging Success: Prints the resolution and size of the captured image.

  • Serving the Image:

    • Sets the content length and MIME type as image/jpeg.

    • Writes the image data directly to the client.

void handleJpgHi()

{

  if (!esp32cam::Camera.changeResolution(hiRes)) {

    Serial.println("SET-HI-RES FAIL");

  }

  serveJpg();

}

 


  • handleJpgHi: Switches the camera to high resolution using esp32cam::Camera.changeResolution(hiRes) and calls serveJpg.

  • Error Logging: If the resolution change fails, it logs a failure message to the Serial Monitor.

void  setup(){

  Serial.begin(115200);

  Serial.println();

  {

    using namespace esp32cam;

    Config cfg;

    cfg.setPins(pins::AiThinker);

    cfg.setResolution(hiRes);

    cfg.setBufferCount(2);

    cfg.setJpeg(80);

 

    bool ok = Camera.begin(cfg);

    Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");

  }

  WiFi.persistent(false);

  WiFi.mode(WIFI_STA);

  WiFi.begin(WIFI_SSID, WIFI_PASS);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

  }

  Serial.print("http://");

  Serial.println(WiFi.localIP());

  Serial.println("  /cam-hi.jpg");


 

  server.on("/cam-hi.jpg", handleJpgHi);

 

 

  server.begin();

}


  Serial Initialization:

  • Initializes the serial port for debugging.

  • Sets baud rate to 115200.

  Camera Configuration:

  • Sets pins for the AI Thinker ESP32-CAM module.

  • Configures the default resolution, buffer count, and JPEG quality (80%).

  • Attempts to initialize the camera and logs the status.

  Wi-Fi Setup:

  • Connects to the specified Wi-Fi network in station mode.

  • Waits for the connection and logs the device's IP address.

  Web Server Routes:

  • Maps URL endpoint ( /cam-hi.jpg).

  •   Server Start:

  • Starts the web server.

void loop()

{

  server.handleClient();

}


  • server.handleClient(): Continuously listens for incoming HTTP requests and serves responses based on the defined endpoints.

Summary of Workflow

  1. The ESP32-CAM connects to Wi-Fi and starts a web server.

  2. URL endpoint /cam-hi.jpg) lets the user request images at high resolution.

  3. The camera captures an image and serves it to the client as a JPEG.

  4. The system continuously handles new client requests.


Python code breakdown

Importing Libraries


import cv2

import requests

import numpy as np



  • cv2: OpenCV library for image processing.

  • requests: To fetch the image frames from the ESP32-CAM over HTTP.

  • numpy (np): For array operations, used here to handle the byte stream received from the ESP32-CAM.



ESP32-CAM URL


ESP32_CAM_URL = "http://192.168.1.104/cam-hi.jpg"


  • Replace this URL with the actual IP address of your ESP32-CAM on your local network. The endpoint "/cam-hi.jpg" returns the latest frame captured by the ESP32-CAM.


Loading Haar Cascades


frontal_face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")

profile_face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_profileface.xml")



  • Haar cascades are pre-trained classifiers provided by OpenCV to detect objects like faces.

  • haarcascade_frontalface_default.xml: Detects frontal faces.

  • haarcascade_profileface.xml: Detects side/profile faces.


Frame Processing Function


def process_frame(frame):

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)



  • cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY): Converts the image to grayscale, which is required by Haar cascades for face detection.

Frontal Face Detection


 frontal_faces = frontal_face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(20, 20))


detectMultiScale: Detects objects in the image.

  • scaleFactor=1.1: Specifies how much the image size is reduced at each scale.

  • minNeighbors=5: Minimum number of neighbouring rectangles required for positive detection.

  • minSize=(20, 20): Minimum size of detected objects.

Profile Face Detection


 profile_faces = profile_face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(20, 20))

  • Same as frontal detection but uses the profile cascade for side faces.

Drawing Rectangles for Faces


    for (x, y, w, h) in frontal_faces:

        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)

        cv2.putText(frame, "Frontal Face", (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)


  • Draws a red rectangle around each detected frontal face.

  • Adds the label "Frontal Face" above the rectangle.


    for (x, y, w, h) in profile_faces:

        cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)

        cv2.putText(frame, "Profile Face", (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)


  • Draws a blue rectangle for each detected profile face.

  • Labels it as "Profile Face."


Adding Face Counts

    cv2.putText(frame, f"Frontal Faces: {len(frontal_faces)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

    cv2.putText(frame, f"Profile Faces: {len(profile_faces)}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)


  • Displays the count of detected frontal and profile faces on the top-left of the frame.





Main Loop


while True:

    response = requests.get(ESP32_CAM_URL)



  • Continuously fetches images from the ESP32-CAM.

Handle the Image Response

    if response.status_code == 200:

        img_arr = np.asarray(bytearray(response.content), dtype=np.uint8)

        frame = cv2.imdecode(img_arr, cv2.IMREAD_COLOR)


  • Converts the HTTP response to a NumPy array.

  • Decodes the byte array into an OpenCV image using cv2.imdecode.


Process and Display the Frame

        processed_frame = process_frame(frame)

        cv2.imshow("Face Detector", processed_frame)

  • Processes the frame using the process_frame function.

  • Displays the processed frame in a window titled "Face Detector."

Quit on Key Press

        if cv2.waitKey(1) & 0xFF == ord('q'):

            break


  • Checks if the 'q' key is pressed to exit the loop.

Error Handling

    else:

        print("Failed to fetch image from ESP32-CAM")


  • Prints an error message if the ESP32-CAM fails to provide an image.


Clean Up

cv2.destroyAllWindows()


  • Closes all OpenCV windows when the program exits.












Summary of the Workflow

  1. Setup:

    • The code connects to the ESP32-CAM via its IP address to fetch image frames in real time.

    • It loads pre-trained Haar Cascade classifiers for detecting frontal and profile faces.

  2. Continuous Image Fetching:

    • The program enters a loop where it fetches a new image frame from the ESP32-CAM using an HTTP GET request.

  3. Image Processing:

    • The image is converted into a format usable by OpenCV.

    • The frame is processed to:

      • Convert it to grayscale (required for Haar Cascade detection).

      • Detect frontal faces and profile faces using the respective classifiers.

  4. Face Detection and Visualization:

    • For each detected face:

      • A rectangle is drawn around it:

        • Red for frontal faces.

        • Blue for profile faces.

      • A label ("Frontal Face" or "Profile Face") is added above the rectangle.

    • The count of detected frontal and profile faces is displayed on the frame.

  5. Display:

    • The processed frame, with visual indicators and counts, is displayed in a window titled "Face Detector."

  6. User Interaction:

    • The program continues fetching, processing, and displaying frames until the user presses the 'q' key to quit.

  7. Error Handling:

    • If the ESP32-CAM fails to provide an image, an error message is printed, and the loop continues.

  8. Cleanup:

    • Upon exiting the loop, all OpenCV windows are closed to release resources.


Key Workflow Steps:

  1. Fetch Image → 2. Convert Image → 3. Detect Faces → 4. Annotate Frame → 5. Display Frame → 6. Repeat Until Exit.


Testing


  1. Power up the ESP32-CAM and connect it to Wi-Fi.

  2. Run the Python script. Make sure that the ESP32-CAM URL is correctly set.

  3. See the result of counting the faces in the display.

  4. You can test with real-life people and photos. 

                 Fig: Face  counting

Troubleshooting:

  • Guru Meditation Error: Ensure stable power to the ESP32-CAM.

  • No Image Display: Check the IP address and ensure the ESP32-CAM is accessible from your computer.

  • Library Conflicts: Use a virtual environment to isolate Python dependencies.

  • Dots at the time of uploading the code: Immediately press the RST button.

  • Multiple failed upload attempts despite pressing the RST button: Restart your computer and try again. 

To wrap up

This project demonstrates an effective implementation of a face-counting system using ESP32-CAM and Python. The system uses the ESP32-CAM’s capability to capture and serve high-resolution images over HTTP. The Python client uses OpenCV's Haar cascade classifiers to effectively detect and count frontal and profile faces in each frame. It provides real-time feedback.

This project can be adapted for various applications, such as crowd monitoring, security, and smart building management. It provides an affordable and flexible solution. 

Future improvements can be made using advanced face detection algorithms like DNN-based models. This project highlights how simple hardware and software integration can address complex problems in computer vision.

Object Counting Project using ESP32-CAM and OpenCV

Imagine a real-time object counting system that is budget-friendly and easy to implement. You can achieve this goal with an ESP32-CAM. Today we will build an ESP32-CAM Object Counting System. This project is a combination of the power of embedded systems and computer vision.

The main processor of the system is ESP32-CAM, a budget-friendly microcontroller with an integrated camera. This tiny powerhouse captures live video streams and transmits them over Wi-Fi. On the other side, a Python-based application processes these streams, detects objects using image processing techniques, and displays the count dynamically.

Whether it’s tracking inventory in a warehouse, monitoring traffic flow, or automating production lines, this system is versatile and adaptable. You can implement this project with a minimum number of components. It is quite easy.

Join us as we explore how to build this smart counting system step-by-step. You'll learn to configure the ESP32-CAM, process images in Python, and create a seamless, real-time object detection system. Let’s see how to bring this project to life!

System Architecture of the ESP32-CAM Object Counting System

The ESP32-CAM Object Counting System is built on a modular and efficient architecture, combining hardware and software components to achieve real-time object detection and counting. Below is a detailed breakdown of the system architecture:

1. Hardware Layer

  1. ESP32-CAM Module

    • Acts as the primary hardware for image capture and Wi-Fi communication.

    • Equipped with an onboard camera to stream live video at different resolutions.

    • Connects to a local Wi-Fi network to transmit data.

  2. Power Supply

    • Provides stable power to the ESP32-CAM module, typically via a USB connection or external battery pack.

2. Communication Layer

  1. Wi-Fi Connection

    • The ESP32-CAM connects to a local Wi-Fi network to enable seamless data transmission.

    • Uses HTTP requests to serve video streams at different resolutions.

  2. HTTP Server on ESP32-CAM

    • Runs a lightweight web server on port 80.

    • Responds to specific endpoints (/cam-lo.jpg, /cam-mid.jpg, /cam-hi.jpg) to provide real-time image frames at requested resolutions.


3. Processing Layer

  1. ESP32-CAM Side

    • Captures and processes raw image data using the onboard camera.

    • Serves the images as JPEG streams through the HTTP server.

  2. Python Application on Host Machine

    • Receives image streams from the ESP32-CAM using HTTP requests.

    • Processes the images using OpenCV for: 

      • Grayscale conversion.

      • Noise reduction with Gaussian blur.

      • Edge detection by using the Canny algorithm.

      • Contour detection to identify objects in the frame.

    • Counts the detected objects and updates the display dynamically.


4. User Interaction Layer

  1. Live Video Feed

    • Displays the real-time video stream with contours drawn around detected objects.

  2. Object Count Display

    • Provides a dynamic count of detected objects in the video feed.

    • The count is displayed on the console or integrated into a graphical interface.

  3. User Commands

    • Enables interaction through keyboard inputs (e.g., pressing 'a' to print the object count or 'q' to quit the application).

5. System Workflow

  1. The ESP32-CAM captures live video and streams it as JPEG images over a Wi-Fi network.

  2. The Python application on the host machine fetches the image frames via HTTP requests.

  3. The fetched images undergo processing in OpenCV to detect and count objects.

  4. The processed video is displayed, and the object count is dynamically updated based on user input.


This architecture ensures a clear separation of tasks, with the ESP32-CAM handling image capture and streaming, and the Python application focusing on image processing and visualization. The modular design makes it easy to expand or adapt the system for various applications.

List of components

Components

Quantity

ESP32-CAM WiFi + Bluetooth Camera Module

1

FTDI USB to Serial Converter 3V3-5V

1

Male-to-female jumper wires

4

Female-to-female jumper wire

1

MicroUSB data cable

1

Circuit diagram

The following is the circuit diagram for this project.

Fig: Circuit diagram

ESP32-CAM WiFi + Bluetooth Camera Module

FTDI USB to Serial Converter 3V3-5V (Voltage selection button should be in 5V position)

5V

VCC

GND

GND

UOT

Rx

UOR

TX

IO0

GND (FTDI or ESP32-CAM)

Programming

Board installation

If it is your first project with any board of the ESP32 series, you need to do the board installation first. If ESP32 boards are already installed in your Arduino IDE, you can skip this installation section. You may also need to install the CP210x USB driver.

  • Go to File > preferences, type https://dl.espressif.com/dl/package_esp32_index.json and click OK. 

Fig: Board Installation

  • Go to Tools>Board>Boards Manager and install the ESP32 boards. 

Fig: Board Installation

Install the ESP32-CAM library

  • Download the ESP32-CAM library from Github (the link is given in the reference section). Then install it by following the path sketch>include library> add.zip library. 

Now select the correct path to the library, click on the library folder and press open.

Board selection and code uploading

Connect the camera board to your computer. Some camera boards come with a micro USB connector of their own. You can connect the camera to the computer by using a micro USB data cable. If the board has no connector, you have to connect the FTDI module to the computer with the data cable. If you never used the FTDI board on your computer, you will need to install the FTDI driver first.

  • After connecting the camera,  Go to Tools>boards>esp32>Ai thinker ESP32-CAM

Fig: Camera board selection

After selecting the board, select the appropriate COM port and upload the following code:

#include

#include

#include

const char* WIFI_SSID = "Hamad";

const char* WIFI_PASS = "barsha123";

WebServer server(80);

static auto loRes = esp32cam::Resolution::find(320, 240);

static auto midRes = esp32cam::Resolution::find(350, 530);

static auto hiRes = esp32cam::Resolution::find(800, 600);

void serveJpg()

{

  auto frame = esp32cam::capture();

  if (frame == nullptr) {

    Serial.println("CAPTURE FAIL");

    server.send(503, "", "");

    return;

  }

  Serial.printf("CAPTURE OK %dx%d %db\n", frame->getWidth(), frame->getHeight(),

                static_cast(frame->size()));

 

  server.setContentLength(frame->size());

  server.send(200, "image/jpeg");

  WiFiClient client = server.client();

  frame->writeTo(client);

}

void handleJpgLo()

{

  if (!esp32cam::Camera.changeResolution(loRes)) {

    Serial.println("SET-LO-RES FAIL");

  }

  serveJpg();

}

void handleJpgHi()

{

  if (!esp32cam::Camera.changeResolution(hiRes)) {

    Serial.println("SET-HI-RES FAIL");

  }

  serveJpg();

}

void handleJpgMid()

{

  if (!esp32cam::Camera.changeResolution(midRes)) {

    Serial.println("SET-MID-RES FAIL");

  }

  serveJpg();

}

void  setup(){

  Serial.begin(115200);

  Serial.println();

  {

    using namespace esp32cam;

    Config cfg;

    cfg.setPins(pins::AiThinker);

    cfg.setResolution(hiRes);

    cfg.setBufferCount(2);

    cfg.setJpeg(80);

    bool ok = Camera.begin(cfg);

    Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");

  }

  WiFi.persistent(false);

  WiFi.mode(WIFI_STA);

  WiFi.begin(WIFI_SSID, WIFI_PASS);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

  }

  Serial.print("http://");

  Serial.println(WiFi.localIP());

  Serial.println("  /cam-lo.jpg");

  Serial.println("  /cam-hi.jpg");

  Serial.println("  /cam-mid.jpg");

  server.on("/cam-lo.jpg", handleJpgLo);

  server.on("/cam-hi.jpg", handleJpgHi);

  server.on("/cam-mid.jpg", handleJpgMid);

  server.begin();

}

void loop()

{

  server.handleClient();

}

After uploading the code, disconnect the IO0 pin of the camera from GND. Then press the RST pin. The following messages will appear.

Fig: Code successfully uploaded to ESP32-CAM

You have to copy the IP address and paste it into the following part of your Python code.

Python code

Copy-paste the following Python code and save it using a Python interpreter. 

import cv2

import urllib.request

import numpy as np


url = 'http://192.168.1.101/'  # Update the URL if needed

cv2.namedWindow("live transmission", cv2.WINDOW_AUTOSIZE)

while True:

    img_resp = urllib.request.urlopen(url + 'cam-lo.jpg')

    imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)

    img = cv2.imdecode(imgnp, -1)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    canny = cv2.Canny(cv2.GaussianBlur(gray, (11, 11), 0), 30, 150, 3)

    dilated = cv2.dilate(canny, (1, 1), iterations=2)

    (Cnt, _) = cv2.findContours(dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # Draw contours

    cv2.drawContours(img, Cnt, -1, (0, 255, 0), 2)

    # Display the number of counted objects on the video feed

    count_text = f"Objects Counted: {len(Cnt)}"

    cv2.putText(img, count_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)


    cv2.imshow("live transmission", img)

    cv2.imshow("mit contour", canny)


    key = cv2.waitKey(5)

    if key == ord('q'):

        break


cv2.destroyAllWindows()

Setting Up Python Environment

Install Dependencies:

1)Create a virtual environment:
python -m venv venv

source venv/bin/activate  # Linux/Mac

venv\Scripts\activate   # Windows

2)Install required libraries:

pip install opencv-python numpy

After setting the Pythong Environment, run the Python code. 


ESP32-CAM code breakdown

#include

#include

#include


  • #include : Adds support for creating a lightweight HTTP server.

  • #include : Allows the ESP32 to connect to Wi-Fi networks.

  • #include : Provides functions to control the ESP32-CAM module, including camera initialization and capturing images.

 

const char* WIFI_SSID = "SSID";

const char* WIFI_PASS = "password";

 


  • WIFI_SSID and WIFI_PASS: Define the SSID and password of the Wi-Fi network that the ESP32 will connect to.

 WebServer server(80);


  • WebServer server(80): Creates an HTTP server instance that listens on port 80 (default HTTP port).

 

static auto loRes = esp32cam::Resolution::find(320, 240);

static auto midRes = esp32cam::Resolution::find(350, 530);

static auto hiRes = esp32cam::Resolution::find(800, 600);


esp32cam::Resolution::find: Defines three camera resolutions:

  • loRes: Low resolution (320x240).

  • midRes: Medium resolution (350x530).

  • hiRes: High resolution (800x600).

void serveJpg()

{

  auto frame = esp32cam::capture();

  if (frame == nullptr) {

    Serial.println("CAPTURE FAIL");

    server.send(503, "", "");

    return;

  }

  Serial.printf("CAPTURE OK %dx%d %db\n", frame->getWidth(), frame->getHeight(),

                static_cast(frame->size()));

 

  server.setContentLength(frame->size());

  server.send(200, "image/jpeg");

  WiFiClient client = server.client();

  frame->writeTo(client);

}

 

 


  • esp32cam::capture: Captures a frame from the camera.

  • Failure Handling: If no frame is captured, it logs a failure and sends a 503 error response.

  • Logging Success: Prints the resolution and size of the captured image.

  • Serving the Image:

    • Sets the content length and MIME type as image/jpeg.

    • Writes the image data directly to the client.

void handleJpgLo()

{

  if (!esp32cam::Camera.changeResolution(loRes)) {

    Serial.println("SET-LO-RES FAIL");

  }

  serveJpg();

}

 

void handleJpgHi()

{

  if (!esp32cam::Camera.changeResolution(hiRes)) {

    Serial.println("SET-HI-RES FAIL");

  }

  serveJpg();

}

 

void handleJpgMid()

{

  if (!esp32cam::Camera.changeResolution(midRes)) {

    Serial.println("SET-MID-RES FAIL");

  }

  serveJpg();

}

 


  • handleJpgLo: Switches the camera to low resolution using esp32cam::Camera.changeResolution(loRes) and calls serveJpg.

  • handleJpgHi: Switches to high resolution and serves the image.

  • handleJpgMid: Switches to medium resolution and serves the image.

  • Error Logging: If the resolution change fails, it logs a failure message to the Serial Monitor.

void  setup(){

  Serial.begin(115200);

  Serial.println();

  {

    using namespace esp32cam;

    Config cfg;

    cfg.setPins(pins::AiThinker);

    cfg.setResolution(hiRes);

    cfg.setBufferCount(2);

    cfg.setJpeg(80);

 

    bool ok = Camera.begin(cfg);

    Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");

  }

  WiFi.persistent(false);

  WiFi.mode(WIFI_STA);

  WiFi.begin(WIFI_SSID, WIFI_PASS);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

  }

  Serial.print("http://");

  Serial.println(WiFi.localIP());

  Serial.println("  /cam-lo.jpg");

  Serial.println("  /cam-hi.jpg");

  Serial.println("  /cam-mid.jpg");

 

  server.on("/cam-lo.jpg", handleJpgLo);

  server.on("/cam-hi.jpg", handleJpgHi);

  server.on("/cam-mid.jpg", handleJpgMid);

 

  server.begin();

}


  Serial Initialization:

  • Initializes the serial port for debugging.

  • Sets baud rate to 115200.

  Camera Configuration:

  • Sets pins for the AI Thinker ESP32-CAM module.

  • Configures the default resolution, buffer count, and JPEG quality (80%).

  • Attempts to initialize the camera and logs the status.

  Wi-Fi Setup:

  • Connects to the specified Wi-Fi network in station mode.

  • Waits for the connection and logs the device's IP address.

  Web Server Routes:

  • Maps URL endpoints (/cam-lo.jpg, /cam-hi.jpg, /cam-mid.jpg) to their respective handlers.

  Server Start:

  • Starts the web server.

void loop()

{

  server.handleClient();

}


  • server.handleClient(): Continuously listens for incoming HTTP requests and serves responses based on the defined endpoints.

Summary of Workflow

  1. The ESP32-CAM connects to Wi-Fi and starts a web server.

  2. URL endpoints (/cam-lo.jpg, /cam-mid.jpg, /cam-hi.jpg) let the user request images at different resolutions.

  3. The camera captures an image and serves it to the client as a JPEG.

  4. The system continuously handles new client requests.


Python code breakdown

Importing Libraries


import cv2

import urllib.request

import numpy as np

  • cv2: OpenCV library for image processing.

  • urllib.request: Used to fetch images from the live camera feed via an HTTP request.

  • numpy: Helps in manipulating and decoding image data into arrays.


Camera Setup


url = 'http://192.168.1.101/'  # Update the URL if needed

cv2.namedWindow("live transmission", cv2.WINDOW_AUTOSIZE)

  • url: The IP address of the camera with the endpoint cam-lo.jpg to get the image stream.

  • cv2.namedWindow: Creates a window to display the live video feed.


Main Loop


while True:

  • A loop continuously fetches and processes frames from the camera feed until the user quits by pressing 'q'.


Fetching the Image


img_resp = urllib.request.urlopen(url + 'cam-lo.jpg')

imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)

img = cv2.imdecode(imgnp, -1)

  • urllib.request.urlopen: Sends an HTTP GET request to the camera URL and retrieves an image. Here you can use ‘cam-hi.jpg’ or ‘cam-mid.jpg’ instead. You can use any of the three resolutions of images and see which one gives you the best result.  

  • bytearray: Converts the image data into a binary format for processing.

  • np.array: Converts the binary data into a NumPy array.

  • cv2.imdecode: Decodes the NumPy array into an image (OpenCV-readable format).


Image Preprocessing


gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

canny = cv2.Canny(cv2.GaussianBlur(gray, (11, 11), 0), 30, 150, 3)

dilated = cv2.dilate(canny, (1, 1), iterations=2)

  • cv2.cvtColor: Converts the image to grayscale for easier edge detection.

  • cv2.GaussianBlur: Applies a Gaussian blur to reduce noise and detail in the image.

    • Parameters (11, 11) specify the kernel size (area used for the blur).

  • cv2.Canny: Performs edge detection.

    • 30, 150: Lower and upper thresholds for edge detection.

    • 3: Size of the Sobel kernel.

  • cv2.dilate: Expands the edges detected by the Canny algorithm to close gaps and make objects more defined.

    • (1, 1): Kernel size for dilation.

    • iterations=2: Number of times the dilation is applied.


Finding Contours


(Cnt, _) = cv2.findContours(dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

  • cv2.findContours: Finds the outlines of objects in the binary (edge-detected) image.

    • dilated.copy(): A copy of the dilated image is used to find contours.

    • cv2.RETR_EXTERNAL: Retrieves only the outermost contours.

    • cv2.CHAIN_APPROX_NONE: Retains all contour points without compression.

  • Cnt: List of all detected contours.


Drawing Contours


cv2.drawContours(img, Cnt, -1, (0, 255, 0), 2)

  • cv2.drawContours: Draws the detected contours onto the original image.

    • img: The image to draw on.

    • Cnt: The list of contours.

    • -1: Indicates that all contours should be drawn.

    • (0, 255, 0): The color of the contours (green in BGR format).

    • 2: Thickness of the contour lines.


Displaying the Object Count


count_text = f"Objects Counted: {len(Cnt)}"

cv2.putText(img, count_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

  • f"Objects Counted: {len(Cnt)}": A formatted string showing the number of detected objects.

  • cv2.putText: Adds the text onto the image.

    • img: The image to draw on.

    • (10, 30): Coordinates of the bottom-left corner of the text.

    • cv2.FONT_HERSHEY_SIMPLEX: The font style.

    • 1: Font scale (size).

    • (0, 0, 255): Text color (red in BGR format).

    • 2: Thickness of the text.


Displaying the Video Feed


cv2.imshow("live transmission", img)

cv2.imshow("mit contour", canny)

  • cv2.imshow: Displays images in separate windows.

    • "live transmission": Shows the original image with contours and text.

    • "mit contour": Shows the edge-detected binary image.


Keyboard Interaction

    key = cv2.waitKey(5)

    if key == ord('q'):

        break

  • cv2.waitKey: Waits for 5 milliseconds for a key press.

  • ord('q'): Checks if the 'q' key is pressed, and if so, breaks the loop to exit the program.

Cleanup

cv2.destroyAllWindows()

cv2.destroyAllWindows: Closes all OpenCV windows when the loop ends.


Summary of Workflow

  1. Fetches the image from the live camera feed.

  2. Processes the image to detect edges and contours.

  3. Counts and draws contours on the image.

  4. Displays the image with the object count overlaid.

  5. Exits when 'q' is pressed.

Testing


  1. Power up the ESP32-CAM and connect it to Wi-Fi.

  2. Run the Python script, ensuring the ESP32-CAM URL is correctly set.

  3. See the result of counting the objects in the display.

Note: The background and the objects should be of different colors.  If you place black objects on a black background, you will get the wrong results.

Fig: coin counting

Troubleshooting:

  • Guru Meditation Error: Ensure stable power to the ESP32-CAM.

  • No Image Display: Check the IP address and ensure the ESP32-CAM is accessible from your computer.

  • Library Conflicts: Use a virtual environment to isolate Python dependencies.

To wrap up

This project demonstrates a seamless integration of an ESP32-CAM module and Python to build a real-time object-counting system. By using the ESP32-CAM's ability to capture and serve images over Wi-Fi, coupled with Python's powerful OpenCV library, we achieved an efficient and cost-effective solution for object counting and detection.

Throughout the tutorial, we explored each component in detail, from setting up the ESP32-CAM to processing live image streams with Python. Along the way, we learned to customize image resolutions, handle server routes, and enhance detection accuracy using OpenCV functions like edge detection and contour analysis.

This project not only provides a practical application but also serves as a solid foundation for more advanced computer vision systems. Whether you aim to integrate machine learning for object classification or scale this system for industrial monitoring, the possibilities are vast.

We hope this tutorial has inspired you to dive deeper into the world of IoT and computer vision. Happy building!

Getting Started with ESP32-CAM | Pinout, Features, Programming, Code Uploading

In today’s tutorial, we’ll show you how to program the ESP32-CAM module. ESP32-CAM module is suitable for building basic surveillance or monitoring systems. Its price is quite reasonable. You can use it for lots of AI-based projects like object detection, face recognition etc. 

However, many users face hard luck when setting up and uploading code to ESP32-CAM development boards. This tutorial will provide you with a guideline for successfully programming the ESP32-CAM.  

Overview of the ESP32-CAM Development Board

The ESP32-CAM is a standalone development board that integrates an ESP32-S chip, a camera module, onboard flash memory, and a microSD card slot. It features built-in Wi-Fi and Bluetooth connectivity and supports OV2640 or OV7670 cameras with a resolution of up to 2 megapixels.

Key Features:

  • Ultra-small 802.11b/g/n Wi-Fi + Bluetooth/BLE SoC module

  • Low-power, dual-core 32-bit processor with a clock speed of up to 240MHz and computing power of 600 DMIPS

  • 520 KB built-in SRAM and 4M external PSRAM

  • Supports multiple interfaces: UART, SPI, I2C, PWM, ADC, and DAC

  • Compatible with OV2640 and OV7670 cameras and includes built-in flash storage

  • Enables Wi-Fi-based image uploads and supports TF cards

  • Multiple sleep modes for power efficiency

  • Operates in STA, AP, and STA+AP modes

Specifications:

  • Dimensions: 27 × 40.5 × 4.5 mm

  • SPI Flash: Default 32Mbit

  • RAM: 520KB internal + 4M external PSRAM

  • Bluetooth: BT 4.2 BR/EDR and BLE

  • Wi-Fi Standards: 802.11 b/g/n/e/i

  • Interfaces: UART, SPI, I2C, PWM

  • TF Card Support: Up to 16GB (4G recommended)

  • GPIO Pins: 9 available

  • Image Output Formats: JPEG (only with OV2640), BMP, Grayscale

  • Antenna: Onboard with 2dBi gain

  • Security: WPA/WPA2/WPAS-Enterprise/WPS

  • Power Supply: 5V

  • Operating Temperature: -20°C to 85°C

Power Consumption:

  • Without flash: 180mA @ 5V

  • With max brightness flash: 310mA @ 5V

  • Deep sleep mode: 6mA @ 5V

  • Modem sleep mode: 20mA @ 5V

  • Light sleep mode: 6.7mA @ 5V

ESP32-CAM Pinout

The ESP32-CAM module has fewer accessible GPIO pins compared to a standard ESP32 board since many are allocated for the camera and SD card module. Certain pins should be avoided during programming:

  • GPIO1, GPIO3, and GPIO0 are essential for uploading code and should not be used for other functions.

  • GPIO0 is linked to the camera XCLK pin and should remain unconnected during normal operation. It must be pulled to GND only when uploading firmware.

  • P_OUT Pin: Labeled as VCC on some boards, this pin provides 3.3V or 5V output depending on the solder pad configuration. It cannot be used to power the board—use the dedicated 5V pin instead.

  • GPIO 2, 4, 12, 13, 14, and 15 are assigned to the SD card reader. If the SD card module is unused, these pins can be repurposed as general I/O.

Notably, the onboard flash LED is connected to GPIO 4, meaning it may turn on when using the SD card reader. To prevent this behaviour, use the following code snippet:

SD_MMC.begin("/sdcard", true);


For an in-depth explanation of the ESP32-CAM pinout and GPIO usage, refer to the Random Nerd Tutorials guide: ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained.

Schematic 

Following is a full schematic of the ESP32-CAM. 

Driver installation

You need to install the CP210X driver on your computer to get the ESP32-CAM working. You can download the driver from here

Board installation

No matter which method you choose to program your ESP32-CAM, you need to do the board installation. If ESP32 boards are already installed in your Arduino IDE, feel free to skip this installation section. Go to File > preferences, type https://dl.espressif.com/dl/package_esp32_index.json and click OK. 

  • Go to Tools>Board>Boards Manager and click ‘install’. 

Install the ESP32-CAM library.

  • Download the ESP32-CAM library from Github (the link is given in the reference section). Follow the path sketch>include library> add.zip library. 

Now select the correct path to the library, click on the library folder and press open. 

Board selection and code uploading

Connect the camera board to your computer. Some camera boards come with a micro USB connector of their own. You can connect the camera to the computer using a micro USB data cable. If the board has no connector, you need to connect the FTDI module to the computer with the data cable. You will need to install the FTDI driver first.

  • When you’re done with the connection,  Go to Tools>boards>esp32>Ai thinker ESP32-CAM

After selecting the board, select the appropriate COM port and upload the following code:

Method 1: Using the ESP32-CAM Programmer Shield

ESP32-CAM programmer shield is made exclusively to program the ESP32-CAM. The shield is equipped with a USB-to-serial converter.  The built-in USB-to-serial converter simplifies the process of connecting the board to a computer for programming and debugging. It also includes a microSD card slot for expanded storage, enabling easy data storage and retrieval. Additionally, the shield features a power switch and an LED indicator, allowing for straightforward power control and status monitoring. With its compact design and user-friendly functionality, the ESP32-CAM-MB Programmer Shield is a valuable tool for developers working with the ESP32-CAM-MB board.

Connecting ESP32-CAM with the Programmer Shield

Just connect the ESP32-CAM module on top of the Programming Shield as shown below, and connect a USB cable from the Programming Shield to your computer. Now you can program your ESP32-CAM.

Connecting the Programming Shield to Your Computer

First, take a functional  USB cable.  It should be securely connected and to the USB port of your computer. When plugged in, you should hear a notification sound from your computer. A red LED on the Programming Shield should illuminate. Next, confirm that you have selected the AI Thinker ESP32-CAM board and the appropriate Serial Port. Refer to the image below for guidance.

Press the upload button to upload your code.

Press the IOo button of the programming shield. 

The text ‘connecting’ should appear in the output panel.

While holding down the IOo button, press the RST button and release. See the following picture to know the location of the RST button, that you need to press.

When the dots in the text “Connecting …..” stop appearing you can release the IO0 button as well. If the following text appears, it indicates that the code is being uploaded:

Running Mode

When the code is uploaded, you will see the message “Hard resetting via RTS pin…” in the Output Panel. You must press the RST button on the ESP32-CAM module to run the uploaded program. Avoid using the RST button on the Programming Shield. Also, do not press the IO0 button.

Test Code for ESP32-CAM with Programming Shield

This simple Blink program turns on the Flash LED on the ESP32-CAM for 10 milliseconds, then waits for 2 seconds before repeating the cycle.

int flashPin = 4;

void setup() {

  pinMode(flashPin, OUTPUT);

}


void loop() {

  digitalWrite(flashPin, HIGH);

  delay(10);

  digitalWrite(flashPin, LOW);

  delay(2000);

}

You will see the LED flashing if the code is uploaded without any problem. 

Method 2: Programming ESP32-CAM with FTDI programmer.

List of components



Components

Quantity

ESP32-CAM WiFi + Bluetooth Camera Module

1

FTDI USB to Serial Converter 3V3-5V

1

Male-to-female jumper wires

4

Female-to-female jumper wire

1

MicroUSB data cable

1

Circuit diagram

Following is the circuit diagram of this project.


ESP32-CAM WiFi + Bluetooth Camera Module FTDI USB to Serial Converter 3V3-5V (Voltage selection button should be in 5V position)

5V

VCC

GND

GND

UOT

Rx

UOR

TX

IO0

GND (FTDI or ESP32-CAM)

Programming

Testing Code for ESP32-CAM with FTDI Programmer

This code functions similarly to a standard Blink program but gradually increases the brightness of the flash LED over 255 steps before turning it off for a second and repeating the cycle.

int flashPin = 4;


void setup() {

  pinMode(flashPin, OUTPUT);

}


void loop() {

  for (int brightness = 0; brightness < 255; brightness++) {

    analogWrite(flashPin, brightness);

    delay(1);

  }

  analogWrite(flashPin, 0);

  delay(1000);

}


Since programming the ESP32-CAM (even with the FTDI Programmer) can be cumbersome, it’s advisable to first verify the functionality of the SD card and camera before attempting more complex projects. The following sections outline how to do this.


Testing the SD Card

The ESP32-CAM officially supports up to 4GB microSD cards, but 8GB and 16GB cards generally work fine. Larger cards require reformatting to FAT32, which can be done using guiformat.exe from Ridgecrop.

The test program below creates a file, writes a test message to it, and reads back the content. If the output matches expectations, the SD card is functioning correctly.

#include "SD_MMC.h"

#include "FS.h"

#include "LittleFS.h"


int flashPin = 4;


void setup() {

  Serial.begin(115200);  

  SD_MMC.begin();

  LittleFS.begin(true);


  // Create and write a test file

  File file = LittleFS.open("/test.txt", FILE_WRITE);

  file.print("*** Test successful ***");

  file.close();


    file = LittleFS.open("/test.txt");

  while (file.available()) {

    Serial.write(file.read());

  }

  file.close();


  // Set the flash LED as output 

  pinMode(flashPin, OUTPUT);

// turn the LED off

  analogWrite(flashPin, 0);

}


void loop() {

}


Code Breakdown

1. Libraries & Initialization:


#include "SD_MMC.h"

#include "FS.h"

#include "LittleFS.h"


Additionally, we define flashPin to control the flash LED:

int flashPin = 4;


2. Setup Function:
The setup() function initializes serial communication at 115200 baud:

Serial.begin(115200);


Then we need to initialize the SD card and LittleFS file system. The argument true ensures that LittleFS is formatted if it isn't already:

SD_MMC.begin();

LittleFS.begin(true);


A file named test.txt is created, a test message is written, and the file is closed:

File file = LittleFS.open("/test.txt", FILE_WRITE);

file.print("*** Test successful ***");

file.close();


The file is reopened in read mode, its contents are printed to the serial monitor, and then it is closed:

file = LittleFS.open("/test.txt");

while (file.available()) {

  Serial.write(file.read());

}

file.close();


We need to turn off the flash LED. 

pinMode(flashPin, OUTPUT);

analogWrite(flashPin, 0);


3. Loop Function:
The loop() function remains empty since the entire process occurs within setup(). 


Serial Monitor Output

If the SD card test is successful, you will see *** Test successful ***

in the Serial Monitor.

This confirms that data can be written to and read from the SD card.

Additional SD Card Testing

For more extensive diagnostics, you can use the SDMMC_Test.ino example provided in the ESP32 library. This program includes additional debugging information and can be accessed via:

File > Examples > Examples for AI-Thinker ESP32-CAM > SDMMC > SDMMC_Test

Testing the Camera

After verifying the SD card, the next step is to test the camera module. The following is a simplified program that captures an image each time the ESP32-CAM is reset. The image will be saved in the SD card.

#include "esp_camera.h"

#include "soc/rtc_cntl_reg.h"

#include "SD_MMC.h"

#include "EEPROM.h"

// Pin configuration for AI-Thinker ESP32-CAM module

#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

void configCamera() {

  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_UXGA;

  config.jpeg_quality = 10;

  config.fb_count = 2;

  esp_camera_init(&config);

}

unsigned int incrementCounter() {

  unsigned int counter = 0;

  EEPROM.get(0, counter);

  EEPROM.put(0, counter + 1);

  EEPROM.commit();

  return counter;

}


void captureImage() {

  camera_fb_t* fb = esp_camera_fb_get();

  unsigned int counter = incrementCounter();

  String filename = "/pic" + String(counter) + ".jpg";

  Serial.println(filename);

  File file = SD_MMC.open(filename.c_str(), FILE_WRITE);

  file.write(fb->buf, fb->len);

  file.close();

  esp_camera_fb_return(fb);

}

void setup() {

  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);

  Serial.begin(115200);

  SD_MMC.begin();

  EEPROM.begin(16);

  configCamera();

  captureImage();

  esp_deep_sleep_start();

}

void loop() {

}

Code Overview

  • The configCamera() function sets up the camera with the appropriate pin configurations.

  • The incrementCounter() function tracks the number of captured images using EEPROM.

  • The captureImage() function takes a picture and saves it to the SD card.

  • The setup() function initializes the camera and SD card, captures an image, and puts the ESP32-CAM into deep sleep mode to conserve power.

This basic framework can be expanded for use cases such as motion-triggered or interval-based image capture.

Frequently Asked Questions

Here are some common problems that you may face while working with the ESP32-CAM.  You have provided the solutions too. 

Wi-Fi Connectivity

Q: Why isn’t my ESP32-CAM connecting to Wi-Fi?
A: Check if you have entered the right SSID and password.

Camera & Image Quality

Q: Is there any way to improve the image quality of the camera?
A: Adjust the camera settings in your code, experimenting with different resolutions and frame rates for the best results.

Q: Why are my images blurry or unclear?
A: Poor lighting conditions can degrade image quality. Ensure proper lighting, fine-tune camera settings, and remove the protective lens foil.

Serial Communication & Code Upload

Q: Why the camera is not responding to serial monitor commands?
A:  Check the connections between the board and the computer. Also, confirm that the baud rate (115200) in your code matches the serial monitor settings.

Q: Why do I see  “Timed out waiting for packet header” during code upload?

 A: An unstable USB connection may cause this problem. You can try a different USB cable or PORT. 

Q: What to do if the  ESP32-CAM freezes during code upload?
A: Disconnect and reconnect the USB cable, reset the board, and attempt the upload again. Check that your code isn't causing crashes.

Q: How to resolve the error “A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header”?
A: This may be caused by an incorrect baud rate or a faulty USB cable. 

SD Card Issues

Q: Why isn’t my SD card being detected?
A: The SD card is properly inserted and formatted as FAT32. Cards between 4GB and 16GB work best, while higher-capacity cards may cause issues.

Power & Performance

Q: My ESP32-CAM gets hot—should I be concerned?
A: It’s normal for the board to warm up during operation, but excessive heat could indicate a short circuit or power issue.

Q: How can I reduce power consumption?
A: Use sleep modes.

Other Camera Issues

Q: Why isn’t my ESP32-CAM capturing images?
A: Check that the camera module is securely connected, and ensure the correct camera module type is defined in your code.

Q: Can I use ESP32-CAM for video streaming?
A: Use a web server library such as ESP32-CAM-Webserver to stream video over Wi-Fi. Ensure your network can handle the required bandwidth.

Bootloader & OTA Programming

Q: Why won’t my ESP32-CAM enter bootloader mode?
A: Ensure GPIO0 is connected to GND, and press the reset button at the correct moment to enter bootloader mode.

Q: Can I upload code wirelessly?
A: Yes, for that you have to use Over-The-Air (OTA) programming. 

If you continue to experience issues, double-check the wiring, connections, and settings in your code.

Web-Server Based Weather Monitoring System Using ESP32

Abstract: This paper is written to represent a web-server based real-time weather monitoring system implemented using the ESP32 module. The system is designed to measure the weather conditions like temperature, pressure, humidity etc, in its vicinity. This system continuously provides real-time data (weather conditions) over limited or controlled areas, for example, agriculture fields, homes or a particular room, industries etc. Although we have satellites for weather monitoring but to perform research over a particular area, the data observed should be highly accurate which is not possible with satellites. To implement an IoT network we need to use a webserver to continuously store and display the real-time data which can be accessed globally. ’ThingSpeak’ is a web service where one can upload and access (globally) with internet-connected devices. ESP32 will be acting as an interface medium between the various sensors and the web-server. ESP32 module is also responsible for collecting, processing and then communicating the data to the server. The real-time data stored on the web server can be further used for research and analysis of weather conditions of a particular place.

Keywords

ESP32, IoT, Temperature sensor, Humidity sensor, Pressure sensor, Altitude sensor, Arduino IDE, ThingSpeak.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

Introduction

The evolving generation of wireless technology has made human life a lot easier. Where everything is online and automatic we can easily monitor multiple things virtually from anywhere in the world. The WSN (wireless sensor networks) and Internet of things or IoT play an important role in implementing and accessing these wireless technologies. Smart homes, smart cities and smart weather monitoring systems are examples of such technologies where things are quite simpler or easier.

In this web-server based weather monitoring system, the weather data (from the surrounding environment or of a particular location) like temperature, humidity, pressure etc. is measured with the help of some sensors and then the collected data will be stored on a server after being processed by a microcontroller. Our daily activities are inseparable from weather conditions and various environmental factors. The real-time data collected can be used in research and analysis and the results can be helpful in human life and for improving environmental conditions as well.

The Internet of Things is a system made up of multiple inter-related computing devices. The main factor ‘things’ in IoT is designated to a component that is capable of communicating data over a network (IoT), the thing could be animals, a digital machine, a sensor, a human being etc. Each component of the Internet of Things network is given an individual or a distinct identity and the ability to communicate data or information over a wireless network that is too without the intervention of a human or a computer [8].

An interface medium capable of collecting, controlling, and communicating data among transmitter and recipient electronic equipment or servers is required to build the IoT network[9].

The ESP32 microcontroller series was developed by Espressif Systems. This module (the ESP32) includes a 2.4GHz Wi-Fi chip, memory, a 32-bit Tensilica microcontroller, an antenna, peripheral interfacing abilities, power management modules, and more. This ESP32 module is excellent for the Internet of things because of all of its technological and infrastructural aspects [10].

DHT11 and BMP280 sensors are used to collect the data from their surrounding environment and then communicate the data to the ESP32 module over a particular protocol [11].

The application of this weather monitoring system can also play an important role in the field of agriculture[12 ] to increase productivity, research application, and reducing manpower (by reducing the need to manually monitor the field status). Sometimes in a particular agricultural zone that is hazardous for a human beings, it is quite difficult to manually (offline) monitor the environment or weather conditions. In such cases, this web server based or online weather monitoring system can be of great importance.

Fig. 1

Hardware and Software Components

The list and quantity of the components required to implement the web server based weather monitoring system are shown in Table1.

Table: 1

DHT11

Fig. 2 DHT11 sensor

DHT11 sensor (or temperature and humidity sensor) is a sensor module used to measure humidity and temperature from its surrounding. This sensor module is responsible for monitoring the ambient temperature and humidity of a given area. An NTC (negative temperature co-efficient) temperature sensor and a resistive type humidity sensor make up the sensor. An 8-bit microcontroller is also included. The microcontroller performs ADC (analogue to digital conversion) and outputs a digital signal via the single wire protocol [13].

Some of the technical specifications of the DHT11 sensor are:

Table:2  DHT11 technical specifications

DHT11 sensors can also be used to create a wired sensor system with up to 20 meters of cable.

To measure temperature and humidity, two DHT modules (DHT11 and DHT22) are available on the market. Both modules serve the same purpose, but they have different specifications. The DHT22 sensor, for example, has a wider range of temperature and humidity sensitivity. However, DHT22 is more expensive than DHT11. As a result, you can choose to use any of the modules as per your needs.

Interfacing DHT11 with ESP32[14]

Table.3  Interfacing DHT11 with ESP32

BMP280

Another sensor we are using is the BMP280. The BMP280, also known as the barometric pressure sensor, is a temperature, pressure, and altitude sensor. This sensor's small size and low power consumption make it suitable for mobile applications, GPS modules, and battery-powered devices, among other things[15].

The Bosch BMP280 is based on Bosch's validated ‘Piezo-resistive pressure sensor technology’, which features high accuracy, long-term stability, linearity, and EMC robustness.

The barometric pressure sensor (280) is the successor to the BMP180 sensor, and it is mostly preferred in all areas where precise temperature and pressure measurements are required.

Fig.3  BMP280 Sensor

Fitness, indoor navigation, and GPS refinement are all new technologies which require relative accuracy, and the BMP280 is ideal for them. This module is preferred over the other available modules for temperature records or measurement because of its low TCO (Temperature coefficient of Offset).

The temperature measured with the BMP280 sensor is more accurate than the DHT11 sensor. BMP80 provides a 0.01°C accuracy rate.

Some technical specifications of the BMP280 sensor are:

Table:4  BMP280 Technical specifications

ThingSpeak web service

A web server is a place where one can store data online and can access that data at any time and from anywhere in the world [16]. A real-time data is created with the help of a web-server. There are various web services available to store real-time data for research and analysis like AWS (Amazon Web Service), Azure, Firebase etc.

We are using the ThinSpeak web service provided by MathWorks which allows us to send sensor readings/data to the cloud. The ThingSpeak is an open source data platform for the Internet of Things (IoT) applications. We can also visualize and act on or access the data (calculate the data) sent to the ThingSpeak server from ESP32. Two different types of channels are available to store data on the ThingSpeak server namely ‘Public Channel’ and ‘Private Channel’ and one can use either of the available channels to store and display data [17].

ThingSpeak is frequently used for IoT prototyping and proof-of-concept systems that require analytics[18].

Software Used

We need to give instructions to our ESP32 module so that it can interface, read data from DHT11 and BMP280 sensors and then finally publish the collected data to the ThingSpeak server. Arduino IDE is an integrated development environment used to write, compile and debug the program for the ESP32 module[19].

Fig. Arduino IDE

Process Flow

The process flow of our weather monitoring system is shown below in Chart 1. The process starts with the initialization of ESP32 module which is acting as an interface medium between the sensor modules and the web-server. The ESP32 wi-fi module is continuously searching for the network credentials as per the instruction provided. After connecting to the internet the sensor modules will be initialized and the real-time data [22] collected from the surrounding environment will be pushed to the ThingSpeak web server[23].

Flow Chart: 1

Results

The results observed from the implemented weather monitoring system are shown below. We observed four different environmental conditions which include temperature, humidity, pressure and altitude. The sensor data collected by ESP32 from DHT11 and BMP280 sensors is published to the ThingSpeak web server. On ThingSpeak we have created a channel that contains four fields to store four different environmental factors temperature, humidity, pressure and altitude.

Fig. Hardware

In fig. 4 we can see the ‘Field 1’ which is containing the temperature readings published or communicated from the ESP32 module and saved on the ThingSpeak server.

Similarly, fields 2, 3, and 4 are displaying the humidity, pressure and altitude respectively.

Fig. 4 Temperature (°C)

Fig. 5 Humidity

Fig. 6 Pressure (hPa)

Fig. 7 Altitude

Each factor is monitored at different intervals of time to observe the variations in various environmental factors. From table 5 we can see the various environmental factors and their values at different time intervals for the approximate duration of 24hrs.

Table 5 Variations in weather conditions

Conclusion

We observed the weather conditions (that includes temperature, humidity, pressure and altitude) with our “Web-server based weather monitoring system using ESP32”. The observed real time data is stored on the ThingSpeak server which can be accessed globally. The different values of each (mentioned earlier) environmental factor at different intervals in time are also observed (given in table 5) and the observed result clearly shows the changes in the weather conditions for a full day cycle. Hence, we have successfully implemented and tested the web server based weather monitoring system with ESP32 and ThingSpeak web server.

References

  • Maier, A., Sharp, A. and Vagapov,  Y., November  “Comparative  analysis  and practical implementation  of  the  ESP32  microcontroller  module  for  the  internet  of things”  2017 .
  • Prisma Megantoro, Brahmantya Aji Pramudita, Vigneshwaran Pandi, “Real-time monitoring system for weather and air pollutant measurement with HTML-based UI application” June 2021.
  • Foughali Karim, Karim Fathallah, Ali Frihida, “Monitoring System using web of things in precision agriculture” 2017.
  • J.Shah and B. Mishra, “IoT enabled environmental monitoring system for smart cities,” in 2016 International Conference on Internet of Things and Applications (IOTA), 2016.
  • P.Susmitha , G. Sowmyabala, “ Design and Implementation of Weather Monitoring and Controlling System” July 2014.
  • S.Navulur, A. S. C. S. Sastry, M. N.  Giri Prasad,  “Agricultural  management  through  wireless  sensors  and internet of things” .
  • K.Siva, S. Ram, and A. N. P. S. Gupta, “IoT based Data Logger System for weather monitoring using Wireless sensor networks,” 2016
  • Ferdin Joe John Joseph, “IoT Based Weather Monitoring System for Effective Analytics”, 2249 – 8958, Volume-8 Issue-4, April, 2019.
  • A F Pauzi, MZ Hasan, “Development of IoT Based Weather Reporting System”, 2020.
  • ESP32-IoT Development Framework, https://www.espressif.com/en/products/sdks/esp-idf
  • Carlo Guarnieri Calo Carducci, Antonello Monti, Markus Hans Schraven, Markus Schumacher, Dirk Mueller, “Enabling ESP32 based IoT Applications in Building Automation Systems”, 2019.
  • R.K. M. Math and N. V Dharwadkar, “IoT Based Low-cost Weather Station and Monitoring System for Precision Agriculture in India”, 2018 (2nd International Conference on I-SMAC).
  • N. Tianlong, “Application of Single Bus Sensor DHT11 in Temperature Humidity Measure and Control System [J]”, 2010.
  • “Create a Web Server With ESP32”, https://www.theengineeringprojects.com/2021/11/create-a-web-server-with-esp32.html
  • ThinSpeak, https://thingspeak.com/pages/learn_more
  • T. Thilangam. J, T. S. Babu, and B. S. Reddy, “Weather monitoring system application using LabView”, 2nd International Conference on I-SMAC, 2018.
  • J.Weiss and R. Yu, "Wireless Sensor Networking for the Industrial Internet of Things".
  • Gaurav Verma, Pranjal Mittal, Shaista Farheen, “Real Time Weather Prediction System Using IoT and Machine Learning.
  • R.Shete, S. Agrawal, “IoT based Urban Climate Monitoring using Raspberry Pi”, International Conference on Signal Processing and Communication, 2016.

Reading Data from Firebase Database with ESP32

Internet of Things is a system of multiple inter-related computing devices. The factor ‘thing’ in IoT is designated to an entity capable of communicating data over a network (IOT), which can be a digital machine, sensor, human being, animals etc. Each component that is included in IoT network is assigned with an unique identity called UID and the ability to communicate data over IoT network without any external human or computer intervention.

Hello readers, I hope you all are doing great. In our previous tutorial, we discussed how to upload data to Firebase Real-time Database using ESP32. In this tutorial, we will learn how to read the data stored on the Firebase Database with ESP32.

We can access the data stored in Firebase database from anywhere in the world, which makes this preferable in IoT applications.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

Project overview

In our previous tutorial, we learnt how to upload an integer value (for demonstration) to Firebase real-time database. So, in this tutorial we will learn how to fetch or receive those integer values from Firebase database.

To access real-time data, we are using two ESP boards where one is used to upload/store the real-time data to the Firebase database and another to read the data stored on the firebase.

Although, it is not required to use two ESP boards, we can also access the previously saved data on the Firebase database with only a single ESP32/ESP8266 board.

We can use the same code for both ESP32 and ESP8266 but we need to make some changes like some of the libraries will be different for ESP8266 and the selection of ESP8266 development board while uploading the code with Arduino IDE.

Fig. 1 Reading data from firebase

Firebase

Google's Firebase real-time database is a development platform that includes a number of services for managing and authenticating data.

Firebase is a mobile and web app development platform (that also works well with Android APIs) that includes features such as Firebase Cloud, real-time data, and Firebase authentication, among others.

According to Firebase's official documentation (https://firebase.google.com/docs/database), when a user creates a cross-platform application using JavaScript SDKs for Android or Apple, all clients share a single database.

Fig. 1 Firebase Real-time database and ESP32

The following are the main features of the Firebase Real-time database:

  • Firebase applications remain responsive even when they are not connected to the internet. If any changes were missed while in offline mode, they will be automatically synchronized once connectivity is restored.
  • Unlike hypertext transfer protocol requests, Firebase RTDB uses data synchronization to update changes in the database within milliseconds, making it easier to access the database from a web browser or a mobile device.

Firebase in IoT:

The Internet of Things, also known as IoT, is the interconnection of physical objects or devices with sensors and software accessing capabilities in order to communicate data or information over the internet.

We need an interface medium that can fetch, control, and communicate data between sender and receiver electronics devices or servers in order to build an IoT network.

The Firebase real-time database gives you a place to store data from sensors on your level device. With Android APIs, Firebase performs admirably.

Firebase is especially useful for storing data from sensors and syncing it between users in real-time in data-intensive Internet of things (IoT) applications. For the sake of simplicity and clarity, we can say that it is a Google cloud service for real-time collaborative apps.

Components required:

  • ESP32 development board
  • Arduino IDE for programming
  • Firebase account
  • Firebase API key and project URL

Programming with Arduino IDE

We are using Arduino IDE to compile and upload code into the ESP32 module. You must have ESP32 board manager installed on your Arduino IDE to program the ESP32 module. To know more about Arduino IDE and how to use it, follow our previous tutorial i.e., on ESP32 programming series. The link is given below:

https://www.theengineeringprojects.com/2021/11/introduction-to-esp32-programming-series.html

Steps to add the necessary libraries in Arduino IDE:

  • Go to Tools >> Manage Libraries.

Fig. 2 manage libraries

  • Search for the Firebase ESP Client library in Library Manager and click Install.
  • We are attaching an image, where we are installing the Firebase ESP-Client (2.3.7 version) library.

Fig. 3 Install Firebase ESP Client Library

Firebase API key and Project URL

We have already posted a tutorial on our website on getting started with Firebase real-time database and how to post or upload data to Firebase database from ESP32. Where we discussed, how to create a project on Firebase real-time database, authentication, how to access the API key and project URL etc.

So now we do not need to create a new project, we are using the same project and hence same API key and project URL to read or download the data from Firebase real-time database.

  • To access the project API key, go to Firebase website and open the project you have created.
  • Go to left sidebar >> setting >> project setting and copy the Web API key.
  • Paste that API key in your Arduino IDE code.

Fig. 4 Project Setting

Fig. 5 Project API key

  • Got to Real-time database on left sidebar and copy the project URL.
  • Paste the project URL in your Arduino IDE code.

Fig. 6 Project URL

 

Code

//--add necessary header files

#include <WiFi.h>

#include <Firebase_ESP_Client.h>

#include "addons/TokenHelper.h" //Provide the token generation process info.

#include "addons/RTDBHelper.h" //Provide the real-time database payload printing info and other helper functions.

// Insert your network credentials

#define WIFI_SSID "ssid"

#define WIFI_PASSWORD "password"

// Insert Firebase project API Key

#define API_KEY "replace this with your project API key"

// ----Insert real-time database URL

#define DATABASE_URL "replace this with your project URL"

//Define Firebase Data object

FirebaseData fbdo;

FirebaseAuth auth;

FirebaseConfig config;

unsigned long sendDataPrevMillis = 0;

int read_data;

bool signupSuccess = false;

void setup() {

Serial.begin(115200);

WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

Serial.print("Connecting to Wi-Fi");

while (WiFi.status() != WL_CONNECTED) {

Serial.print(".");

delay(200);

}

Serial.println();

Serial.print("Connected to... ");

Serial.println(WiFi.localIP());

Serial.println();

// Assigning the project API key

config.api_key = API_KEY;

//Assign the project URL

config.database_url = DATABASE_URL;

/// check signup statue

if (Firebase.signUp(&config, &auth, "", "")) {

Serial.println("ok");

signupSuccess = true;

}

else {

Serial.printf("%s\n", config.signer.signupError.message.c_str());

}

// Assign the callback function for token generation task

config.token_status_callback = tokenStatusCallback;

Firebase.begin(&config, &auth);

Firebase.reconnectWiFi(true);

}

void loop()

{

if (Firebase.ready() && signupSuccess && (millis() -

sendDataPrevMillis > 8000 || sendDataPrevMillis == 0))

{

sendDataPrevMillis = millis();

if (Firebase.RTDB.getInt(&fbdo, "/test/int"))

{

if (fbdo.dataType() == "int")

{

read_data = fbdo.intData();

Serial.print("Data received: ");

Serial.println(read_data); //print the data received from the Firebase database

}

}

else

{

Serial.println(fbdo.errorReason()); //print he error (if any)

}

}

}

Code Description

  • The libraries we are using are:
    • The first one is h, which is used to enable the Wi-Fi module and hence wireless network connectivity.
    • Another library we are using is the h which is responsible for interfacing ESP32 and Firebase Real-time Database.

Fig. 7 Header files

  • We also need to add two helper libraries (required by the Firebase library).
  • The TokenHelper library is responsible for managing the token generation process.
  • On the other hand, the RTDBHelper library is responsible for providing helper functions to print data coming from the Firebase database.

Fig. 8 Helper libraries

  • Next, we need to insert the project API key obtained from the Firebase project setting page.

Fig. 9 Insert API key

  • Similarly, insert the RTDB (real-time database) URL.

Fig. 10 RTDB URL

  • Next, we are defining three firebase data objects, responsible for linking App to Firebase.

Fig. 11 Firebase Data Objects

  • Enter the network credentials in place of SSID and PASSWORD.

Fig. 12 Enter Network credentials

Setup

  • Initialize the serial monitor at 115200 baud rate for debugging purpose.
    • begin() function is used to initialize the Wi-Fi module with Wi-Fi credentials used as arguments.
    • The While loop will continuously run until the ESP32 is connected to Wi-Fi network.

Fig. 13 Initialize wifi module

  • If the device is connected to local Wi-Fi network then print the details on serial monitor.
  • localIP() function is used to fetch the IP address.
  • Print the IP address on serial monitor using println() function.

Fig. 14 Fetch/obtain the IP address

  • Here, we are assigning the API key to the firebase configuration.

Fig. 15 configuring API key

  • Similarly, the database URL is also assigned to firebase configuration

Fig. 16 configuring database URL

  • Next, we are checking or verifying the Firebase sign-up status.
  • In the signup() function the last two arguments are empty, indicating the anonymous user.
  • If you have enabled different sign-up methods during the Firebase authentication method like Google account, Facebook etc then you need to add the respective credentials as arguments.
  • The respective results of signup status will be printed on the serial monitor.

Fig. 17 sign up status

  • Next, you need to assign the callback function for token generation.

Fig. 18

Loop()

  • Once the signup is successfully done, we are ready to fetch the data stored on the Firebase real-time database in every 10 seconds.
  • RTDB.getInt() command is used to store the data in /test/int node. But before that we are checking the data type that is ‘int’(integer). If the data type of the message/data received from Firebase RTDB is ‘int’ only then the data will be stored inside the integer type variable i.e., “read_data”.

Fig. 19 Fetch data from Firebase RTDB

  • If the data type is other than integer then an error will be printed on the serial monitor.

Fig. 20

  • Similarly, we can read/fetch various types of data like float, string, array etc. from the firebase database.

Testing

  • Open your Arduino IDE and paste the above code.
  • Change the network credentials, that is the SSID and PASSWORD as per you network setup.
  • Compile and upload the code into ESP32 development board.
  • Before uploading the code make sure that you have selected the correct development board and COM port.

Fig. 21 Select development board and COM port

  • Once the code is uploaded successfully, open the Serial monitor and select the 1115200 baud rate (as per your code instructions).
  • Make sure Wi-Fi to which your ESP device is supposed to connect is ON.
  • Once your ESP device is connected with Wi-Fi, you should see the data fetched from Firebase, printing on the serial monitor with a particular delay (as per the code instructions).

Fig. 22 Data sent Vs Data Received

This concludes the tutorial. I hope you found this of some help and also hope to see you soon with a new tutorial on ESP32.

ESP32 Firebase

Hello readers, I hope you all are doing great. In this tutorial, we will learn how to access Firebase (a real-time database) to store and read values or data with ESP32.

It is Google’s mobile application development platform that can be used to can access, monitor and control ESP32 from anywhere in the world with its (firebase) real-time database.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

What is Firebase?

Firebase real-time database is a development platform provided by Google which included multiple services to manage and authenticate data.

Firebase is basically a mobile and web app development platform I as works great with Android APIs) that includes features like firebase cloud, real-time data and Firebase authentication etc.

As per Firebase’s official documentation (https://firebase.google.com/docs/database), whenever a user creates a cross-platform application like with Android, or Apple, JavaScript SDKs, all the clients share a single.

Fig. 1 Firebase Real-time database and ESP32

The main features of the Firebase Real-time database are:

  • Firebase applications remain responsive even in offline mode. If any changes are missed during the offline mode, then after the connectivity is reestablished those changes will be automatically synchronized.
  • Firebase Real-time database makes it easier to access the database from a web browser or a mobile device.
  • Unlike hypertext transfer protocol requests, Firebase RTDB uses data synchronization which makes it possible to update the changes in the database within milliseconds.

Role of Firebase Realtime Database in IoT

The IoT or Internet of Things is the interconnection of physical objects or devices with sensors and software accessing capabilities to communicate data or information over the internet.

To build an IoT network, we need an interface medium that can fetch, control, and communicate data between sender and receiver electronics devices or servers.

Firebase real-time database provides a platform to store data collected from sensors at the level device. Firebase works great with Android APIs.

Firebase is particularly useful in data-intensive Internet of things (IoT) applications to store from sensors and synch that data between users in real-time. For simplicity or better understanding we can say that it is a cloud service provided by Google for real-time collaborative apps.

Project Overview

  • In this tutorial we are going to create a Firebase project with real-time database to read and store data with ESP32. Steps included to achieve the target are; creating a firebase project, storing data from ESP32 to firebase real-time Database, Reading data from firebase real-time database with ESP32.

Prerequisites

  • ESP32 development board
  • Arduino IDE
  • Necessary Library (Firebase ESP Client)
  • A Google account to access Firebase
 

Getting Started with Firebase

  • Create a project

The steps involved in creating a Firebase project are:

Fig. 2 Get started

  • Click on Create a project.

Fig. 3 Create a project

  • Assign a name to your project and accept the terms and conditions then click on the continue

Fig. 4 project name

  • Disable the “Enable Google Analytics” option and click on real-time.

Fig. 5 Enabling Google Analytics

  • Now your project is ready click the

Fig. 6 Project Created successfully

Authentication

    • Next we need to set the authentication methods for the app.

As per the official firebase documentation at: https://firebase.google.com/docs/auth , the identity of a user is required by most online services or mobile applications or we can say , it handles authentication process and logging in (in this tutorial, the ESP32). Getting to know the identity of a user enables an application to save user data securely in the cloud and provide a consistent personalized service across all of the customer's devices (android phones, computers, applications etc).

  • Click on

Fig. 7 Authentication

  • You will be redirected to a new page, click on ‘get started.
  • There are multiple methods available to authenticate you account, as shown below.
  • Select any of the authentication method.

Fig. 8 Select authentication method

Next thing is creating a real-time database for the project.

  • Creating a Real-time Database
    • Click on the Real-time database given at the left sidebar.

Fig. 9 Real-time database

  • Then, click on Create Database.

Fig. 10 Creating database

  • Select your nearest location.

Fig. 11

  • Select the Start in test mode option and click on enable

Fig. 12 select location

  • Now your database is successfully created. You will be redirected to a new page containing the database URL.
  • Copy the URL and paste in your ESP32 code.
  • Now the next requirement is getting the API key.

Project API

    • Go to left sidebar and click on Project Overview and then project setting.

Fig. 13 Accessing project API key

  • Copy the web API key and paste in your ESP32 code.
  • That’s all about creating a Firebase account, project, and verification. Now, we are ready to interface the database and ESP32 module.

Programming with Arduino IDE

We are using Arduino IDE to compile and upload code into the ESP32 module. You must have the ESP32 board manager installed on your Arduino IDE to program the ESP32 module. To know more about Arduino IDE and how to use it, follow our previous tutorial i.e., on ESP32 programming series. The link is given below:

https://www.theengineeringprojects.com/2021/11/introduction-to-esp32-programming-series.html

Steps to add the necessary libraries in Arduino IDE:

  • Go to Tools >> Manage Libraries.

Fig. 14 manage libraries

  • Search for the Firebase ESP Client library in Library Manager and click Install.
  • We are attaching an image, where we are installing the Firebase ESP-Client (2.3.7 version) library.

Fig. 15 Install Firebase ESP Client Library

Arduino IDE Code ( To store data from ESP32 to Firebase Database)

//--add necessary header files

#include <WiFi.h>

#include <Firebase_ESP_Client.h>

#include "addons/TokenHelper.h" //Provide the token generation process info.

#include "addons/RTDBHelper.h" //Provide the real-time database payload printing info and other helper functions.

// Insert your network credentials

#define WIFI_SSID "replace this with your netwrok SSID"

#define WIFI_PASSWORD "replace this with your wi-fi password"

// Insert Firebase project API Key

#define API_KEY "replace this with your API key"

// ----Insert real-time database URL

#define DATABASE_URL "replace this with your project URL"

//----Define Firebase Data object

FirebaseData fbdo;

FirebaseAuth auth;

FirebaseConfig config;

int value = 10;

bool signupSuccess = false;

unsigned long sendDataPrevMillis = 0;

void setup()

{

Serial.begin(115200);

WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

Serial.print("Connecting to Wi-Fi");

while (WiFi.status() != WL_CONNECTED){

Serial.print(".");

delay(100);

}

Serial.println();

Serial.print("Connected with IP: ");

Serial.println(WiFi.localIP() );

Serial.println();

// Assign the api key ( required)

config.api_key = API_KEY;

// Assign the RTDB URL ( required)

config.database_url = DATABASE_URL;

// Sign up status

if (Firebase.signUp(&config, &auth, "", ""))

{

Serial.println("ok");

signupSuccess = true;

}

else{

Serial.printf("%s\n", config.signer.signupError.message.c_str());

}

/* Assign the callback function for the long running token generation task */

config.token_status_callback = tokenStatusCallback; // see addons/TokenHelper.h

Firebase.begin(&config, & auth);

Firebase.reconnectWiFi( true);

}

 

void loop()

{

if (Firebase.ready() && signupSuccess && (millis() - sendDataPrevMillis >

10000 || sendDataPrevMillis == 0))

{

sendDataPrevMillis = millis();

if (Firebase.RTDB.setInt(&fbdo, "test/int", value))

{

Serial.println("PASSED");

Serial.println("PATH: " + fbdo.dataPath());

Serial.println("TYPE: " + fbdo.dataType());

}

else

{

Serial.println("FAILED");

Serial.println("REASON: " + fbdo.errorReason());

}

value++;

}

}

Before uploading the code in ESP32 board there are some changes you need to make which includes:

  • Adding network credentials
  • Inserting API key
  • Inserting Firebase project URL
  • Installing necessary library files

Code Description

  • The libraries we are using are:
    • The first one is h, which is used to enable the Wi-Fi module and hence wireless network connectivity.
    • Another library we are using is the h which is responsible for interfacing ESP32 and Firebase Real-time Database.

Fig. 16 Header files

  • We also need to add two helper libraries (required by the Firebase library).
  • The TokenHelper library is responsible for managing the token generation process.
  • On the other hand, the RTDBHelper library is responsible for providing helper functions to print data coming from the Firebase database.

Fig. 17 Helper libraries

  • Next, we need to insert the project API key obtained from the Firebase project setting page.

Fig. 18 Insert API key

  • Similarly, insert the RTDB (real-time database) URL.

Fig. 19 RTDB URL

  • Next, we are defining three firebase data objects, responsible for linking App to Firebase.

Fig. 20 Firebase Data Objects

  • Enter the network credentials in place of SSID and PASSWORD.

Fig. 21 Enter Network credentials

  • Next, we are defining some variables to store integer value, status of sign up to firebase account, and delay element etc.

Fig. 22 variable declaration

 

Setup

  • Initialize the serial monitor at 115200 baud rate for debugging purpose.
    • begin() function is used to initialize the Wi-Fi module with Wi-Fi credentials used as arguments.
    • The While loop will continuously run until the ESP32 is connected to Wi-Fi network.

Fig. 23 Initialize wifi module

  • If the device is connected to local Wi-Fi network then print the details on serial monitor.
  • localIP() function is used to fetch the IP address.
  • Print the IP address on serial monitor using println() function.

Fig. 24 Fetch/obtain the IP address

  • Here, we are assigning the API key to the firebase configuration.

Fig. 25 configuring API key

  • Similarly, the database URL is also assigned to the firebase configuration

Fig. 26 configuring database URL

  • Next, we are checking or verifying the Firebase sign-up status.
  • In the signup() function the last two arguments are empty, indicating the anonymous user.
  • If you have enabled different signup methods during the Firebase authentication method like Google account, Facebook etc then you need to add the respective credentials as argument.
  • The respective results of signup status will be printed on the serial monitor.

Fig. 27 sign up status

  • Next, you need to assign the callback function for token generation.

Fig. 28

Loop()

  • If, the sign up status is true (or Successful), then we are ready to send the data from ESP32 to Firebase Real-time database.
  • For demonstration purpose, we are sending integer value to the Firebase database. You can also send a string, float, array, sensor reading etc. as per your requirements.
  • senInt() command is used to send integer values. This command is passing three arguments first on is the firebase database object, the second argument is the database node path and the third one is the ‘value’ we are communicating to Firebase real-tie database.
  • Similarly, we can share string, float, or array etc.

Fig. 29 Loop() function

Testing

  • Open your Arduino IDE and paste the above code.
  • Change the network credentials, that is the SSID and PASSWORD as per you network setup.
  • Compile and upload the code into ESP32 development board.
  • Before uploading the code make sure that you have selected the correct development board and COM port.

Fig. 30 Select development board and COM port

  • Once the code is uploaded successfully, open the Serial monitor and select the 1115200 baud rate (as per your code instructions).
  • Make sure Wi-Fi to which your ESP device is supposed to connect is ON.
  • Go to https://console.firebase.google.com.
  • Select the project you have created.
  • Click on left sidebar and then click on Real-time Database.
  • A new page will open, containing the data uploaded from the ESP32.
  • We have attached an image below for your reference.
  • An integer value will be uploaded to the Firebase Real-time database in every 10 seconds.
  • In the image attached below, you can see three different values displaying. But only the integer value (in yellow color) is active and rest of the data is inactive.

Fig. 31 Result 1

  • The integer value is increasing by 1 in every 10 second.

Fig. 32 Result 2

  • Similarly, we can interface and upload sensor reading to the Firebase database.

This concludes the tutorial. I hope you found this of some help and also hope to see you soon with a new tutorial on ESP32.

ESP32 BMP280 sensor Interfacing with ThingSpeak WebServer

Hello readers, I hope you all are doing great. In this tutorial, we will learn how to interface the BMP280 sensor with the ES32 module to get temperature, pressure and altitude readings. Later, in this tutorial, we will also discuss how to upload these sensor readings to a web server.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

BMP280

BMP280 or Barometric pressure sensor is a module used to measure temperature pressure and altitude. The small size and low power consumption feature of this sensor makes it feasible for battery-powered devices, GPS modules and mobile applications etc.

Fig. 1 BMP280 Sensor

The BMP280 is the product of BOSCH which is based on Bosch’s proven Piezo-resistive pressure sensor technology featured with high accuracy, long term stability, linearity and high EMC robustness.

BMP280 is the successor of the BMP180 sensor and offers high performance in all the areas that require precise temperature and pressure measurements.

Emerging applications like fitness, indoor navigation, GPS refinement requires relative accuracy and BMP280 is perfect for such applications. Very low TCO (Temperature coefficient of Offset ) makes this module preferable over other available modules for temperature measurements.

We can also use a DHT11/DHT22 sensor for temperature and humidity measurements but the BMP280 sensor provides better accuracy (i.e., 0.01°C) than DHT sensors.

Technical specifications of BMP280

  • Operating voltage: 1.8 -3.3V DC
  • Communication protocols supported: SPI, I2C
  • Ultra low power consumption
  • Temperature accuracy: 1°C
  • Temperature range: -40 to 85°C
  • Absolute accuracy : 1 hPa

Components required:

  • ESP32 development board
  • Arduino IDE for programming
  • BMP280 sensor
  • Breadboard
  • Connecting wires

Interfacing BMP280 with ESP32

There are two methods of interfacing BMP280 sensor with ESP32 module:

  1. I2C protocol
  2. SPI protocol

In the bMP280 Sensor module, there are six interfacing pins including VCC and GND.

Fig. Interfacing BMP280 and ESP32

We are using the I2C protocol for interfacing the two (ESP and BMP280) so only SCL and SDA pins will be used with power pins for interfacing. The SDO and CSB pins will be used only if you are using the SPI protocol for interfacing.

Table 1

Programming with Arduino IDE

We are using Arduino IDE to compile and upload code into the ESP32 module. You must have ESP32 board manager installed on your Arduino IDE to program the ESP32 module. To know more about Arduino IDE and how to use it, follow our previous tutorial i.e., on ESP32 programming series. The link is given below:

https://www.theengineeringprojects.com/2021/11/introduction-to-esp32-programming-series.html

Steps to add the necessary libraries in Arduino IDE:

  • Go to Tools >> Manage Libraries.

Fig. 2 manage libraries

  • Search for the Adafruit BMP280 library in Library Manager and click Install.

Fig. 3 Install library

Getting I2C address

  • In order to interface your ESP32 with BMP280, you should know the I2C address of the sensor (BMP280).
  • To obtain the address of the I2C device, copy and paste the below attached code into your Arduino IDE.
  • Compile and upload the code.
  • Open the serial monitor at 115200 baud rate.
  • Now you should see the address of your I2C device printed on the serial monitor.
  • Copy the I2C address and paste in your final code (interfacing esp32 and BMP290 sensor).

#include <Wire.h>

void setup()

{

Wire.begin();

Serial.begin(115200);

Serial.println("\nI2C Scanner");

}

void loop()

{

byte error, address;

int nDevices;

Serial.println("Scanning...");

nDevices = 0;

for(address = 1; address < 127; address++ )

{

Wire.beginTransmission(address);

error = Wire.endTransmission();

if (error == 0)

{

Serial.print("I2C device found at address 0x");

if (address<16)

{

Serial.print("0");

}

Serial.println(address,HEX);

nDevices++;

}

else if (error==4)

{

Serial.print("Unknow error at address 0x");

if (address<16) {

Serial.print("0");

}

Serial.println(address,HEX);

}

}

if (nDevices == 0) {

Serial.println("No I2C devices found\n");

}

else {

Serial.println("done\n");

}

delay(5000);

}

Code (Interfacing and fetching sensor reading from BMP280 with ESP32)

#include <Wire.h>

#include <Adafruit_BMP280.h>

#define BMP_SDA 21

#define BMP_SCL 22

Adafruit_BMP280 bmp280;

void setup()

{

Serial.begin(115200);

Serial.println("Initializing BMP280");

boolean status = bmp280.begin(0x76);

if (!status)

{

Serial.println("Not connected");

}

}

void loop()

{

float temp = bmp280.readTemperature();

Serial.print("temperature: ");

Serial.print(temp);

Serial.println("*C");

float altitude = bmp280.readAltitude(1011.18);

Serial.print("Altitude: ");

Serial.print(altitude);

Serial.println("m");

float pressure = (bmp280.readPressure()/100);

Serial.print("Pressure: ");

Serial.print(pressure);

Serial.println("hPa");

Serial.println(" ");

delay(1000);

}

Code Description

  • The first task is adding necessary header files.
  • We are using two libraries:
    • The Wire.h is used to enable I2C communication/interfacing.
    • The second library we are using is, Adafruit_BMP280.h is to control the BMP sensor and access its respective function.

Fig. 4

  • As we mentioned earlier, we are using the I2C protocol for interfacing BMP280 with ESP32. So we need to define the I2C GPIO pins.
  • In the ESP32 DevKit V1 development board, the GPIO_21 and GPIO_22 are the SDA and SCL pins for I2C communication.
  • Then a bmp280 object is declared for interfacing the sensor.

Fig. 5

Setup()

  • In the setup() function, we are initializing the serial communication at 115200 baud rate for debugging purposes.
  • The BMP280 sensor is initialized with bmp280.begin() function where we are passing the I2C address of the module as an argument.
  • Next, we need to check the status of the interface and the respective result will be printed on the serial monitor.

Fig. 6

Loop()

  • The next task is getting the sensor readings.
  • Here we are measuring three parameters, temperature, humidity and altitude.
  • A float type variable “temp” is defined to store the temperature readings observed from BMP280 sensor using readTemperature() function.

Fig. 7

  • Next, the altitude is measured using bmp280.readAltitude function.
  • We need to adjust the altitude to the local forecast using the multiplying factor.

Fig. 8

  • The bmp280.readPressure() function is used to obtain the pressure using BMP280 sensor.
  • BMP280 sensor readings will be updated every time with a delay of 1 second.

Fig. 9

Testing

  • Open your Arduino IDE and paste the above code.
  • Compile and upload the code into ESP32 development board.
  • Before uploading the code make sure that you have selected the correct development board and COM port.

Fig. 10 Select development board and COM port

  • Once the code is uploaded successfully, open the Serial monitor and select the 1115200 baud rate (as per your code instructions).
  • Now you should see the readings obtained from barometric pressure sensor.

Fig. 11 Serial monitor output

Uploading BMP280 Sensor data to ThingSpeak server

Most of the industries and organizations these days are shifting to the efficient ways of operating things and the IoT internet of things is one of them.

Internet of Things is a system of multiple inter-related computing devices. The factor ‘thing’ in IoT is designated to an entity capable of communicating data over a network (IOT), which can be a digital machine, sensor, human being, animals etc.

Each component that is included in IoT network is assigned with an unique identity called UID and the ability to communicate data over IoT network without any external human or computer intervention.

Fig. 12 IoT

ThingSpeak is an open data platform for the Internet of Things applications. It is a MathWorks web service that allows users to send sensor readings and data to the cloud. We can also visualize and act on the data (calculate the data) that is sent to ThingSpeak by the devices. The information can be saved in both private and public channels.

ThingSpeak is frequently used for IoT prototyping and proof-of-concept devices that require data analysis.

Programming with Arduino IDE

Downloading and installing the required Library file:

  • Follow the link attached below to download the thingSpeak Arduino library:

https://github.com/mathworks/thingspeak-arduino

  • Open the Arduino IDE.
  • Go to Sketch >> Include Library >> Add .ZIP Library and select the downloaded zip file.

Fig. 13 Adding ThingSpeak library

To check whether the library is successfully added or not:

  • Go to Sketch >> Include Library >> Manage Libraries

Fig. 14

  • Type thingspeak in the search bar.

Fig, 15 Arduino IDE Library manager

  • The ThingSpeak library by MathWorks has been successfully downloaded.
 

Getting Started with ThingSpeak

  • To create and account or log in to ThingSpeak (operated by MathWorks) server follow the link: https://thingspeak.com/
  • Click on Get Started for free.

Fig. 16 Getting started for free

  • Enter the required details to create a MathWorks account as shown below:

Fig. 17 Create new account

  • If you have already created a MathWorks account, then click on Sign in.

Fig. 18 MathWorks Sign in

  • Create a channel by clicking on the New Channel

Fig. 19 New Channel

  • Enter the respective details in the channel.
  • Because we are measuring three parameters (temperature, pressure and altitude), hence we need to create three different fields in this channel.

Fig. 20 Creating channel and respective fields

  • Press “save” button.

Fig. 21 save the channel

  • After successfully saving the channel, a new window will open containing the channel details and Channel Stats.
  • In the same window, go to API Keys which contains the Write API keys and Read API keys.
  • Copy the Write API key and paste this in ESP32 Arduino code to upload the sensor readings on ThingSpeak server.
  • You can also customize the chart in Private View. Click on the icon present at the top right menu of Field Chart (in red box) to edit the chart.
  • Edit the details as per your requirements and click on save button to save the details.

Fig. 22 Field Chart Edit

  • Now your ThingSpeak channel is ready to communicate and save/store data.

Code (Arduino IDE)

// ------style guard ----

#ifdef __cplusplus

extern "C"

{

#endif

uint8_t temprature_sens_read();

#ifdef __cplusplus

}

#endif

uint8_t temprature_sens_read();

// ------header files----

#include <WiFi.h>

#include "ThingSpeak.h"

#include <Wire.h>

#include <Adafruit_BMP280.h>

#define BMP_SDA 21

#define BMP_SCL 22

Adafruit_BMP280 bmp280;

// -----netwrok credentials

const char* ssid = "public"; // your network SSID (name)

const char* password = "ESP32@123"; // your network password

WiFiClient client;

// -----ThingSpeak channel details

unsigned long myChannelNumber = 4;

const char * myWriteAPIKey = "9R3JZEVBG73YE8BY";

// ----- Timer variables

unsigned long lastTime = 0;

unsigned long timerDelay = 1000;

 

void setup()

{

Serial.begin(115200); // Initialize serial

Serial.println("Initializing BMP280");

boolean status = bmp280.begin(0x76);

if (!status)

{

Serial.println("Not connected");

}

//Initialize Wi-Fi

WiFi.begin(ssid, password);

Serial.print("Connecting to Wi-Fi");

while (WiFi.status() != WL_CONNECTED)

{

Serial.print(".");

delay(100);

}

Serial.println();

Serial.print("Connected with IP: ");

Serial.println(WiFi.localIP());

Serial.println();

// Initialize ThingSpeak

ThingSpeak.begin(client);

}

void loop()

{

if ((millis() - lastTime) > timerDelay )

{

float temp = bmp280.readTemperature(); //temperature measurement

Serial.print("temperature: ");

Serial.print(temp);

Serial.println("*C");

float altitude = bmp280.readAltitude(1011.18); //altitude measurement

Serial.print("Altitude: ");

Serial.print(altitude);

Serial.println("m");

float pressure = (bmp280.readPressure()/100); //pressure measurement

Serial.print("Pressure: ");

Serial.print(pressure);

Serial.println("hPa");

Serial.println(" ");

ThingSpeak.setField(1, temp );

ThingSpeak.setField(2, altitude);

ThingSpeak.setField(3, pressure);

// Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different

// pieces of information in a channel. Here, we write to field 1.

int x = ThingSpeak.writeFields(myChannelNumber,

myWriteAPIKey );

if(x == 200)

{

Serial.println("Channel update successful." );

}

else

{

Serial.println("Problem updating channel. HTTP error code " + String(x) );

}

lastTime = millis();

}

}

Code Description

We are describing only the ThingSpeak server part as the BMP280 and ESP32 interfacing part has already been discussed in the above code description.

  • The style guard is used at the beginning to declare some function to be of “C” linkage, instead of “C++”
  • Basically, it allows the C++ code to interface with C code.

Fig. 23 Style guard

  • Add the necessary header/library files.
  • We have already discussed above how to download and add the ThingSpeak library file to Arduino IDE.

Fig. 24 Libraries

  • Enter the network credentials (SSID and Password).

Fig. 25

  • A Wi-Fi client is created to connect with ThingSpeak.

Fig. 26

  • Define timer variables.

Fig. 27

  • Add the channel number and API (Write) Key. If you have created only one channel then the channel number will be ‘1’.

Fig. 28

Setup()

    • Initialize the Serial monitor with a 115200 baud rate for debugging purposes.

Fig. 29

  • Set ESP32 Wi-Fi module in station mode using mode() function.
  • Enable ESP32’s Wi-Fi module using begin() function which is using SSID and password as arguments.
  • Wait until the ESP32 is not connected with the wifi network.

Fig. 30

  • Initialize the ThingSpeak server using begin() function that is passing client (globally created) as an argument.

Fig. 31

 

Loop()

  • We are defining three float type variables to save temperature, altitude and pressure measurements respectively.

Fig. 32 Sensor readings

  • Setting up the ThingSpeak fields for respective sensor measurement. The various sensor readings are passed as arguments inside the ThingSpeak.setField() function with there respective filed number.

Fig. 33 setting respective Fields

  • writeFields() function is used to write data to the ThingSpeak server. This function is using the channel number and API key as an argument.

Fig. 34

  • Return the code 200 if the sensor readings are successfully published to ThingSpeak server and print the respective results on the serial monitor.

Fig. 35

Results

  • Open your Arduino IDE and paste the above code.
  • Compile and upload the code into the ESP32 development board.
  • Before uploading the code make sure that you have selected the correct development board and COM port.
  • Make sure the Wi-Fi network to which your ESP device is supposed to connect is active.
  • Open the serial monitor at a 115200 baud rate and press the EN button from ESP32 development.
  • Once your ESP32 is connected with the wi-fi network, open the channel you have created on the ThingSpeak server.
  • Now you see the sensor readings displayed on their respective fields.

Fig. 36 ThingSpeak server

  • You can also compare the data displayed on the server with the serial monitor.

Fig. 37 Sensor readings on the Serial monitor

This concludes the tutorial. I hope you found this of some help and also hope to see you soon with a new tutorial on ESP32.

Update LCD Display with ESP32 Web Server

Hello readers, I hope you all are doing great.

ESP32 is a powerful chip for Internet of Things applications. This tutorial is also based on one of the ESP32 applications in the field of IoT.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

Project Overview

In this tutorial, we will learn how to update LCD display with new data or input using a web server created with ESP32.

Fig. 1

To achieve the target, we will be using an HTML (Hypertext Markup Language) form to provide web input and then update the text displayed on LCD. The values or input received from the webserver will be further stored inside a variable in the code for further use (to display on LCD).

We have already posted a tutorial on LCD (Liquid Crystal Display) interfacing with ESP32. In that tutorial, we demonstrated how to display the hard-coded data (in the ESP32 module) on LCD.

ESP32 Web Server

A web server is computer software and hardware that accepts requests and responds to those requests using HTTP (Hypertext transfer protocol) or HTTPS (HTTP Secure) (HTTP is a network protocol for delivering online content to client user agents).

The ESP32 standalone web server is mobile-enabled and can be accessed from any device with a browser on the local network. B. Mobile phones, computers, laptops, tablets. However, all the devices must be connected to the same WiFi network to which the ESP32 is connected.

Software and Hardware requirements

  • ESP32 development board
  • 16*2 LCD display
  • 10K trim-pot
  • Breadboard or general-purpose PCB
  • Connecting Wires
  • Arduino IDE
  • h, ESPAsynchWenServer.h header files

Interfacing16*2 LCD with ESP32

There are basically two ways to connect the ESP32 to a 16 * 2 LCD display.

  1. Interface with I2C adapter
  2. Direct connection without using I2C adapter.

Connecting an LCD display without an I2C adapter is cheap, but this method requires more connection cables and is complicated to implement. On the other hand, using an I2C adapter reduces complexity but increases cost. In this tutorial, you will connect the ESP32 directly without using an I2C adapter.

Table: 1

Fig. 2: ESP32 and 16*2 LCD interfacing

For more details on interfacing 16*2 LCD with ESP32, follow our previous tutorial at www.theengineeringprojects.com

Programming ESP32

Installing ESP32 board manager in Arduino IDE:

We are using Arduino IDE to compile and upload code into ESP32 module. You must have ESP32 board manager installed on your Arduino IDE to program ESP32 module. To know more about Arduino IDE and how to use it, follow our previous tutorial i.e., on ESP32 programming series. The link is given below:

https://www.theengineeringprojects.com/2021/11/introduction-to-esp32-programming-series.html

Installing necessary libraries:

ESP32 board manager doesn’t come with inbuilt libraries to create an asynchronous web server. So we need to download the library file from external sources and then add into Arduino IDE.

We need to install two library files:

  1. ESPAsynWebServer: Follow the link https://github.com/me-no-dev/ESPAsyncWebServer to download the respective library.
  1. AsyncTCP: You can download the AsyncTCP library from the following link https://github.com/me-no-dev/AsyncTCP

Once you have successfully downloaded the required libraries, next step it to install or add these libraries in Arduino IDE.

To add the libraries in Arduino IDE, go to Sketch >> Include Library >> Add .zip library and then select the downloaded library files.

Fig. 3: adding necessary libraries

Arduino IDE code

#include < WiFi.h >

#include < AsyncTCP.h >

#include < ESPAsyncWebServer.h >

#include < LiquidCrystal.h > // LCD header file

LiquidCrystal lcd (22, 23, 5, 18, 19, 21 );

AsyncWebServer server ( 80 );

// Enter your netwrok credentials

const char* ssid = "replace this with netwrok SSID";

const char* password = "replace this with Password";

const char* PARAM_INPUT_1 = "data_field1";

const char* PARAM_INPUT_2 = "data_field2";

// HTML web page to handle data input fields

const char index_html[] PROGMEM = R"rawliteral(

<!DOCTYPE HTML> <html> <head>

<title> ESP Input Form </title>

<meta name = " viewport" content="width=device-width, initial-scale=1 ">

<style>

html{ font-family: Times New Roman; display: inline-block; text-align: justify;}

</style>

</head> <body>

<form action="/get">

Data_field1: <input type="text" name="data_field1" >

<input type="submit" value="Post ">

</form> <br>

<form action="/get">

Data_field2: <input type="text" name="data_field2">

<input type="submit" value="Post">

</form><br>

</body></html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {

request->send(404, "text/plain", "Not found");

}

void setup() {

 

Serial.begin(115200);

WiFi.mode(WIFI_STA);

WiFi.begin(ssid, password);

if (WiFi.waitForConnectResult() != WL_CONNECTED) {

Serial.println("WiFi Failed!");

return;

}

Serial.println();

Serial.print("IP Address: ");

Serial.println(WiFi.localIP());

//===set LCD

lcd.begin(16, 2);

lcd.clear();

lcd.setCursor(1,0);

server.onNotFound(notFound);

server.begin();

// Send web page with input fields to client

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)

{

request->send_P(200, "text/html", index_html);

});

server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {

String inputMessage;

String inputParam;

// GET input1 value

if (request->hasParam(PARAM_INPUT_1))

{

inputMessage = request->getParam(PARAM_INPUT_1)->value();

inputParam = PARAM_INPUT_1;

}

// GET input2 value

else if (request->hasParam(PARAM_INPUT_2))

{

inputMessage = request->getParam(PARAM_INPUT_2)->value();

inputParam = PARAM_INPUT_2;

}

else

{

inputMessage = " No message sent";

inputParam = " none";

}

Serial.println ( inputMessage );

delay( 1000);

lcd.clear();

lcd.print( inputMessage);

request-> send (200, "text/html", " HTTP GET request sent to ESP32("

+ inputParam + "): " + inputMessage +

"<br><a href=\"/\"> Back to Home Page </a>");

});

}

void loop( )

{

}

Code Description

  • The first step is adding the necessary header files.
  • Here we are using two libraries:
    • The first one is WiFi.h, which is used to enable the Wi-Fi module and hence wireless network connectivity.
    • LiquidCrystal.h is used to call the necessary functions required to interface and control LCD with ESP32.
    • ESPAsynchWenServer library file is responsible for creating an asynchronous web server.
    • AsyncTCP is used to enable a multi-connection network for ESP32 (Espressif’s) microcontroller unit.

Fig. 4: Adding header files

  • Define the data and control pins (of 16*2 LCD) to be interfaced with ESP32.

Fig. 5: LCD data and control pins

  • While creating a web server we also need to assign a port and usually port 80 is used for local web server.

Fig. 6: server port

  • Enter the network credentials in place of SSID and PASSWORD.

Fig. 7: Enter Network credentials

  • The next thing is the declaration of variables for input data fields.

Fig. 8

Creating HTML Form

  • !DOCTYPE html><html> is used to describe/indicate that we are transmitting HTML, this command should always be the first thing we send.
  • <title> tag is used to write a title for the web page.
  • The next line in the code is used to make the web page responsive in any web browser.
  • The <style> tag is used to style the webpage, which includes the type of font, alignment, display etc.

Fig. 9: HTML web page

  • Next comes the HTML form for user input. We are going to create two data input fields for user input and each filed is having a Post button to send the new data string to the ESP device and the variable declared to store the input will be updated.
  • <form> tag is used to create the HTML form. Here we are creating an HTML form with two input fields namely the Data_field2 and Data_filed2 and each field is having individual Post buttons to post the input from the web server to the client.
  • The action attribute is used to specify, where to send the data input provided in the input data fields after pressing the post
  • After pressing the post button a new web page will open, indicating the status whether the input string is successfully posted or not.

Fig. 10: HTML form for data input

  • The two attributes, type and value specifies a button and the text on the button respectively.

Fig. 11: Post button.

  • If we make an invalid request, the notFound() function will be called.
 

Setup

  • Initialize the serial monitor at 115200 baud rate for debugging purpose.
    • begin() function is used to initialize the Wi-Fi module with Wi-Fi credentials used as arguments.
    • The While loop will continuously run until the ESP32 is connected to Wi-Fi network.

Fig. 12

  • If the device is connected to local Wi-Fi network then print the details on serial monitor.
  • localIP() function is used to fetch the IP address.
  • Print the IP address on serial monitor using println() function.

Fig. 13: Fetch/obtain the IP adrress

  • Initialize the 16*2 LCD using begin() function.
  • Clear the previous data from the LCD before printing or displaying the new one using clear() function.
  • Set the cursor position at row 1 and column 0 using setCursor() function.

Fig. 14: Set 16*2 LCD

  • begin() function is used to initialize the web server once ESP32 is connected with the Wi-Fi network.

Fig. 15: Initialize the server

Handling HTTP GET requests

  • The next part in the programming includes handling of HTTP GET requests.
  • When we access the route URL, we send the web page to client along with the data input fields.
  • We have defined a variable namely index_html to save the HTML text.

Fig. 16: Send web page to client

  • Next task is handling what happens when device receive a request on the /get routes.
  • To save input values, we have created two variables: inputPram and

Fig. 17

  • Next we need to check if HTTP get request contains the Data_input1 and Data_input1 These fields values are saved on PRAM_INPUT_1 and PRAM_INPUT2.
  • If the HTTP GET request contains inputs, then the inputMessage1 will be set to the value inserted in the data_field1.

Fig. read the input from HTML form

  • Else there will be no input for inputMessage.

Fig. 18

  • Print the input value saved on variable inputMessage using Serial.print command.
  • clear() command is used to clear the previous data printed on LCD.
  • New data or message received from the web server will be printed on the LCD display using print() function.

Fig. 19

  • After pressing the post button a new web page will open, indicating the status whether the input string is successfully posted or not.

Fig. 20

Testing

  • Open your Arduino IDE and paste the above code.
  • Change the network credentials, that is the SSID and PASSWORD as per you network setup.
  • Compile and upload the code into ESP32 development board.
  • Before uploading the code make sure that you have selected the correct development board and COM port.

Fig. 21: Select development board and COM port

  • Once the code is uploaded successfully, open the Serial monitor and select the 1115200 baud rate (as per your code instructions).
  • Make sure Wi-Fi to which your ESP device is supposed to connect is ON.
  • Once your ESP32 is connected to the internet, the IP address of the device will be printed on the Serial monitor.
  • Copy the IP address.
  • Open the browser and paste the IP address and press
  • A web page with HTML form containing two input fields will open as shown below:

Fig. 22: web Page

  • Enter the text in the HTML form you want to be printed on on the LCD display.
  • Press the Post

Fig. 23: Enter the Input to ESP32

  • After pressing the post button a new web page will open, indicating the status whether the input string is successfully posted or not.

Fig. 24: Input Updated

Fig. 25: IP address and Web Input on serial monitor.

Fig. 26: String input received from Web server, printed on LCD

This concludes the tutorial. We hope you found this of some help and also hope to see you soon with a new tutorial on ESP32.

Server-Sent Events with ESP32 and DHT11

Hello readers, I hope you all are doing great. In this tutorial, we will learn how to update a webpage using Server-Sent Events and the ESP32 web server.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

What is Server-Sent Events (SSE)?

It is a server push technology that enables the client devices to receive automatic updates from a server over HTTP (Hypertext Transfer Protocol) connection. SSE also describes how the server can initiate data transmission towards the client once an initial connection with the client has been established.

We have already posted a tutorial on how to implement Web socket protocol with ESP32 which is also a protocol used to notify events to a web client. Both the Server-Sent Events (SSE) and Web-Socket technologies seem to be quite similar but they are not.

The major difference between the two is that SSE is unidirectional, where the web client can only receive the updates from the ESP32 but it can’t send updates back to ESP32. On the other hand, the Web-socket protocol is bi-directional where both the web client and ESP32 can send and receive updates/events.

Fig. 1 Server-Sent event

How does the Server-Sent Event works?

The Server-Sent Event process initiates with an HTTP request from the web client or web page to the ESP32 web server. After that, the ESP32 is ready to send updates or events to the web client as they happen. But the web client can’t send any response or data to the ESP32 server after the initial handshake takes place.

Server-sent event technology can be used to communicate an event, GPIO states or to send sensor readings to the web client, whenever a new reading is observed.

Project Overview

For demonstration purpose, we are using a DHT11 sensor with the ESP32 module. ESP32 web server will display two things i.e., temperature and humidity observed using the DHT11 sensor. So, whenever a new reading is being observed, the ESP32 sends the reading to the Web Client over Server-sent events. After receiving the latest sensor reading the client updates the web page data.

Software and Hardware requirements

  • ESP32 development board
  • DHT11 sensor
  • Connecting Wires
  • Breadboard
  • Arduino IDE
  • Necessary Libraries

DHT11 (a Temperature and Humidity sensor)

Fig. 2 DHT11 sensor

DHT11 is a humidity and temperature sensor that measures its surrounding environment. It measures the temperature and humidity in a given area. It is made up of an NTC (negative temperature co-efficient) temperature sensor and a resistive humidity sensor. It also has an 8-bit microcontroller. The microcontroller is in charge of ADC (analog to digital conversion) and provides a digital output over the single wire protocol.

The DHT11 sensor can measure humidity from 20% to 90% with +-5 percent accuracy (RH or relative humidity) and temperature from 0 degrees Celsius to 50 degrees Celsius with +-2C accuracy.

DHT11 sensors can also be used to build a wired sensor network with a cable length of up to 20 meters.

Interfacing DHT11 with ESP32 module

Table 1

Note: Connect a 10K resistor between data and power (+5V) pin of DHT11 sensor module.

Fig. 3 ESP32 and DHT11 connections/wiring

Programming with Arduino IDE

We are using Arduino IDE to compile and upload code into the ESP32 module. You must have ESP32 board manager installed on your Arduino IDE to program the ESP32 module. To know more about Arduino IDE and how to use it, follow our previous tutorial i.e., on ESP32 programming series. The link is given below:

https://www.theengineeringprojects.com/2021/11/introduction-to-esp32-programming-series.html

Steps to add the necessary libraries in Arduino IDE:

  • Go to Tools >> Manage Libraries.

Fig. 4 manage libraries

  • Search for the necessary library in Library Manager and click Install.
  • We are attaching an image, where we are installing the DHT11 sensor library.

Fig. 5 Install DHT sensor library

  • Follow the similar procedure for rest of the libraries.
  • After successfully installing all the required libraries close the Library Manager tab.

ESP32 board manager doesn’t come with inbuilt libraries to create an asynchronous web server. So we need to download the library file from external sources and then add into Arduino IDE.

We need to install two library files:

  1. ESPAsynWebServer: Follow the link https://github.com/me-no-dev/ESPAsyncWebServer to download the respective library.
  1. AsyncTCP: You can download the AsyncTCP library from the following link https://github.com/me-no-dev/AsyncTCP

Once you have successfully downloaded the required libraries, next step it to install or add these libraries in Arduino IDE.

To add the libraries in Arduino IDE, go to Sketch >> Include Library >> Add .zip library and then select the downloaded library files.

Fig. 6 adding necessary libraries

Arduino Code

#include <WiFi.h>

#include <AsyncTCP.h>

#include <ESPAsyncWebServer.h>

#include "DHT.h"

#define DHTPIN 4 // Digital pin connected to the DHT sensor

#define DHTTYPE DHT11 // DHT 11

// Initializing the DHT11 sensor.

DHT dht(DHTPIN, DHTTYPE);

// Replace with your network credentials

const char* ssid = "SSID";

const char* password = "password";

// Create AsyncWebServer object on port 80

AsyncWebServer server(80);

// Create an Event Source on /events

AsyncEventSource events("/events");

// Timer variables

unsigned long lastTime = 0;

unsigned long timerDelay = 20000; //20 sec timer delay

//==== Creating web page

const char index_html[] PROGMEM = R"rawliteral(

<!DOCTYPE HTML><html>

<head>

<title>SSE with ESP32 Web Server</title>

<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">

<link rel="icon" href="data:,">

<style>

html {font-family: Times New Roman; display: inline-block; text-align: justify;}

p { font-size: 1.2rem;}

body { margin: 0;}

.topnav { overflow: hidden; background-color: blue; color: white; font-size: 1rem; }

.content { padding: 20px; }

.card { background-color: #ADD8E6; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }

.cards { max-width: 600px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

.reading { font-size: 1.4rem; }

</style>

</head>

<body>

<div class="topnav">

<h1>Server-Sent Events </h1>

<h2> DHT11 Sensor Data </h2>

</div>

<div class="content">

<div class="cards">

<div class="card">

<p> DHT11 Temperature</p><p><span class="reading"><span id="temp">%TEMPERATURE%</span> &deg;C</span></p>

</div>

<div class="card">

<p> DHT11 Humidity</p><p><span class="reading"><span id="hum">%HUMIDITY%</span> &percnt;</span></p>

</div>

</div>

</div>

<script>

if (!!window.EventSource)

{

var source = new EventSource('/events');

source.addEventListener('open', function(e)

{

console.log("Events Connected");

}, false);

source.addEventListener('error', function(e)

{

if (e.target.readyState != EventSource.OPEN)

{

console.log("Events Disconnected");

}

}, false);

source.addEventListener('message', function(e)

{

console.log("message", e.data);

}, false);

source.addEventListener('temperature', function(e)

{

console.log("temperature", e.data);

document.getElementById("temp").innerHTML = e.data;

}, false);

source.addEventListener('humidity', function(e)

{

console.log("humidity", e.data);

document.getElementById("hum").innerHTML = e.data;

}, false);

}

</script>

</body>

</html>)rawliteral";

 

void setup() {

Serial.begin(115200); //initialize serial monitor

//===set and initialize Wi-Fi

WiFi.mode(WIFI_STA);

WiFi.begin(ssid, password);

Serial.print("Connecting to WiFi ..");

while (WiFi.status() != WL_CONNECTED)

{

Serial.print('.');

delay(1000);

}

Serial.print("IP Address: ");

Serial.println(WiFi.localIP()); // print the IP address

//====Initialize DHT11 sensor

dht.begin();

//====Handle Web Server

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){

request->send_P(200, "text/html", index_html);

});

// Handle Web Server Events

events.onConnect([](AsyncEventSourceClient *client)

{

if(client->lastId())

{

Serial.printf("Client reconnected! Last message ID that it got is: %u\n",

client->lastId());

}

// send event with message "hello!", id current millis

// and set reconnect delay to 1 second

client->send("hello!", NULL, millis(), 10000);

});

server.addHandler(&events);

server.begin();

}

void loop()

{

delay(2000);

float humidity = dht.readHumidity();

// Read temperature as Celsius (the default)

float temperature = dht.readTemperature();

// Check if any reads failed and exit early (to try again).

if (isnan(humidity) || isnan(temperature))

{

Serial.println(F("Failed to read from DHT sensor!"));

return;

}

if ((millis() - lastTime) > timerDelay)

{

// Send Events to the Web Server with the Sensor Readings

events.send("ping",NULL,millis());

events.send(String(temperature).c_str(),"temperature",millis());

events.send(String(humidity).c_str(),"humidity",millis());

Serial.print(F("Humidity(%): "));

Serial.println(humidity);

Serial.print(F("Temp.: "));

Serial.print(temperature);

Serial.println(F("°C "));

}

}

Code Description

  • Here we are using four libraries:
    • The first one is WiFi.h, which is used to enable the Wi-Fi module and hence wireless network connectivity.
    • DHT.h is used to call the necessary functions required to interface DHT sensor with ESP32.
    • ESPAsynchWenServer library file is responsible for creating an asynchronous web server.
    • AsyncTCP is used to enable multi-connection network for ESP32 (Espressif’s) microcontroller unit.

Fig. 7 Header files

  • Next step is the declaration of variables for DHT11 sensor.
  • We are declaring 2 variables, the first one is the DHTPIN to store the GPIO number receiving input from DHT11 sensor and another variables is to define the type of DHT (i.e., whether DHT11 or DHT22).

Fig. 8 Global declarations

  • Next we are creating a DHT object called dht in the DHT sensor type (defined earlier) and the DHT pin.

Fig. 9

  • Enter the network credentials in place of SSID and PASSWORD.

Fig. 10 Enter Network credentials

  • While creating a web server we also need to assign a port and usually port 80 is used for local web server.

Fig. 11 Server port

  • Next step is creating a new event source(on /events).

Fig. 12 Event source

  • Timer variable declaration: the timerDelay and lastTime variables are declared to add delay using timer, instead of using delay() function. Here we are adding a delay of 20 seconds which means the web browser will be updated with new sensor reading in every 20 sec.

Fig. 13 Timer Variables

Creating the Web Page

  • !DOCTYPE html><html> is used to describe/indicate that we are transmitting HTML, this command should always be the first thing we send.
  • <title> tag is used to write title for the web page.

Fig. 14

  • The <style> tag is used to style the webpage, which includes the type of font, alignment, display, color, dimensions etc. You can make changes in the <style> tag as per your requirements.

Fig. 15

  • The content, which is to be displayed on the Web page is written inside the <body> tag. The <body> tag includes two headings h1 and h2 and sensor readings (temperature and humidity).

Fig. 16

Initializing an Event-Source connection

  • JavaScript is written inside the inside the <script> tag, which is responsible for initializing an event source connection with the web server and also to handle the events received from the web server.
  • An object EventSource is created and along with that the URL of the webpage sending the updates is also specified.
  • addEventListener() function is used to listen to the messages coming from the web server, once the event source is initiated successfully.

Fig. 17

  • Next task is adding an event listener for Whenever a new temperature reading is observed from the DHT11 sensor, ESP32 sends a “temperature” event to the web client.

Fig. 18

  • Similarly, another event is generated for It prints the latest readings on the web browser & puts the received data into the element with respective ID on the webpage.

Fig. 19

Setup

  • Initialize the serial monitor at a 115200 baud rate for debugging purposes.
    • begin() function is used to initialize the Wi-Fi module with Wi-Fi credentials used as arguments.
    • The While loop will continuously run until the ESP32 is connected to the Wi-Fi network.

Fig. 20

  • If the device is connected to a local Wi-Fi network then print the details on the serial monitor.
  • localIP() function is used to fetch the IP address.
  • Print the IP address on the serial monitor using println() function.

Fig. 21 Fetch/obtain the IP address

 

Fig. 22 Initialize DHT sensor

Handling HTTP GET requests

  • The next part in the programming includes handling HTTP GET requests.
  • When we access the route URL, we send the web page to the client along with the data input fields.
  • We have defined a variable namely index_html to save the HTML text.

Fig. 23

Handling Server Event source

  • The next task is setting up the event source on the webserver.

Fig. 24 Handling server events

 

Initializing web server

  • Initialize the webserver using begin() function.

Fig. 24 initializing web server

 

Loop()

  • DHT11 is a very slow sensor. It takes almost 250ms to read temperature and humidity.
  • So it is preferred to wait a few seconds before a new measurement or updated sensor reading.
  • Next, we are defining a float type variable ‘h’ to store humidity measured from the DHT11 sensor.
  • readHumidity() function is used to observe the humidity value.
  • readTemperature() function is used to read the surrounding temperature with the DHT11 sensor.

Fig. 25

 
  • If somehow the sensor fails to read or observer temperature and humidity values, then the respective results will be printed on the serial monitor.

Fig. 26 If error occurs while reading data from DHT11

Sending Events to the server

  • Send the updated events or the latest observation from the DHT11 sensor the web browser over the local network.
  • The sensor readings will be updated in every 20 second as per the code instructions.

Fig. 27 Sending events to the server

  • Print the temperature and humidity readings (observer form the DHT11 sensor) on the Serial monitor.

Fig. 28 Print Sensor data on the Serial monitor

Testing

  • Open your Arduino IDE and paste the above code.
  • Change the network credentials, that is the SSID and PASSWORD as per you network setup.
  • Compile and upload the code into ESP32 development board.
  • Before uploading the code make sure that you have selected the correct development board and COM port.

Fig. 29 Select development board and COM port

  • Once the code is uploaded successfully, open the Serial monitor and select the 1115200 baud rate (as per your code instructions).
  • Make sure Wi-Fi to which your ESP device is supposed to connect is ON.
  • Once your ESP32 is connected to the internet, the IP address of the device will be printed on the Serial monitor.
  • Copy the IP address.
  • Open the browser and paste the IP address and press
  • A web page will appear, as shown below:

Fig. 30

  • The web page will be updated with new data every 20 seconds, as per the code instructions and we do not even need to refresh the web page for latest event updates due to SSE technology.

Fig. 31

This concludes the tutorial. I hope you found this of some help and also hope to see you soon with a new tutorial on ESP32.

ESP32 DHT11 Interfacing with ThingSpeak WebServer

ESP32 module comes with multiple inbuilt features and peripheral interfacing capability is one of those features. ESP32 module also consists of an inbuilt temperature sensor, but that can only measure the temperature of the ESP32 core not the temperature of the surrounding environment. So it is required to use a peripheral sensor to measure the temperature of the surrounding environment like home, garden, office etc.

Hello readers. I hope you all are doing great. In this tutorial, we will learn how to interface DHT11 (temperature and humidity sensor) with the ESP32. Later in this tutorial, we will discuss how to share the sensor readings obtained from the DHT11 sensor to a web server.

Before moving towards the interfacing and programming part, let’s have a short introduction to the DHT11 sensor, its working and its connections.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

DHT11 (A Temperature and Humidity Sensor)

Fig. 1: DHT11 sensor

DHT11 is used to measure humidity and temperature from its surrounding. It monitors the ambient temperature and humidity of a given area. It consists of an NTC (negative temperature co-efficient) temperature sensor and a resistive type humidity sensor. It also consists of an 8-bit microcontroller. The microcontroller is responsible for performing ADC (analog to digital conversion) and provides a digital output over the single wire protocol.

DHT11 sensor can measure humidity from 20% to 90% with +-5% (RH or relative humidity) of accuracy and can measure the temperature in the range of 0 degrees Celsius to 50 degrees Celsius with +-2C of accuracy.

DHT11 sensors can also be used to implement a wired sensor system using a cable length of up to 20 meters.

There are two DHT modules (DHT11 and DHT22) available in the market to measure temperature and humidity. The purpose of both module are same but with different specifications. Like DHT22 sensor provides broader temperature and humidity sensitivity ranges. But DHT22 is costlier than DHT11. So you can prefer to use any of the module, as per your requirements.

Components required

  • ESP32 development board
  • DHT11 sensor
  • 10K resistor
  • Connecting wires
  • Breadboard

Interfacing DHT11 with ESP32 module

Table: 1

Note: Connect a 10K resistor between data and power (+5V) pin of DHT11 sensor module.

Fig. 2: ESP32 and DHT11 connections/wiring

Arduino Programming

We are using Arduino IDE to compile and upload code into ESP32 module. To know more about Arduino IDE and how to use it, follow our previous tutorial i.e., on ESP32 programming series. Link is given below:

https://www.theengineeringprojects.com/2021/11/introduction-to-esp32-programming-series.html

Adding required libraries in Arduino IDE

DHT11 sensor uses single wire protocol to communicate data which requires a precise timing. In order to interface DHT11 sensor with ESP32 module it is required to add necessary libraries. To install the DHT11 sensor library;

  • Go to Tools >> Manage Libraries.

Fig. 3: manage libraries

 
  • Type DHT in the search bar and install the DHT sensor library as shown below.

Fig. 4: Install DHT sensor library

   

Arduino IDE code to interface DHT11 with ESP32

#include "DHT.h"

#define DHTPIN 4 // Digital pin connected to the DHT sensor

#define DHTTYPE DHT11 // DHT 11

// Initializing the DHT11 sensor.

DHT dht(DHTPIN, DHTTYPE);

void setup() {

Serial.begin(115200);

Serial.println(F("DHT test string!"));

dht.begin();

}

 

void loop() {

// Wait a few seconds between measurements.

delay(2000);

// Reading temperature or humidity takes about 250 milliseconds!

// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)

float h = dht.readHumidity();

// Read temperature as Celsius (the default)

float t = dht.readTemperature();

// Read temperature as Fahrenheit (isFahrenheit = true)

float f = dht.readTemperature(true);

// Check if any reads failed and exit early (to try again).

if (isnan(h) || isnan(t) || isnan(f)) {

Serial.println(F("Failed to read from DHT sensor!"));

return;

}

// Compute heat index in Fahrenheit (the default)

float hif = dht.computeHeatIndex(f, h);

// Compute heat index in Celsius (isFahreheit = false)

float hic = dht.computeHeatIndex(t, h, false);

Serial.print(F("Humidity(%): "));

Serial.println(h);

Serial.print(F("Temp.: "));

Serial.print(t);

Serial.println(F("°C "));

Serial.print(F("Temp.: "));

Serial.print(f);

Serial.println(F("°F "));

Serial.print(F("Heat index: "));

Serial.println(hic);

Serial.println(" ");

Serial.print(F("°C "));

Serial.print(hif);

Serial.println(F("°F"));

}

Code Description

  • Add the necessary header files required to interface the DHT11 sensor.

Fig. 5: Add necessary libraries

  • The next step is the declaration of variables for the DHT11 sensor.
  • We are declaring 2 variables, the first one is the DHTPIN to store the GPIO number receiving input from the DHT11 sensor and another variable is to define the type of DHT (i.e., whether DHT11 or DHT22).

Fig. 6: Global declarations

  • Next, we are creating a DHT object called dht in the DHT sensor type (defined earlier) and the DHT pin.

Fig. 7

 

Setup()

  • Inside the setup function, the first task is initializing the serial monitor at a 115200 baud rate for debugging purposes.
  • Initialize the DHT sensor using begin() function.

Fig. 8

Loop()

  • DHT11 is a very slow sensor. It takes almost 250ms to read temperature and humidity.
  • So it is preferred to wait a few seconds before a new measurement or updated sensor reading.
  • Next, we are defining a float type variable ‘h’ to store humidity measured from the DHT11 sensor.
  • readHumidity() function is used to observe the humidity value.

Fig. 9

  • readTemperature() function is used to read the surrounding temperature with DHT11 sensor.

Fig. 10

  • If somehow the sensor fails to read or observer temperature and humidity values, then the respective results will be printed on the serial monitor.

Fig. 11

  • Another float type variable hif is defined to store the heat index value.
  • computeHeatIndex() function is used to calculate the heat index value.

Fig. 12: Heat index

Results

  • Open the Arduino IDE and paste the above code.
  • Compile and upload the program after selecting the correct development board and COM port.
  • Connect the DHT11 sensor with ESP32 board as per the given circuit instructions.

Fig. ESP32 and DHT11 interfacing

  • Open the serial monitor at 115200 baud rate and press the enable (EN) button from the ESP32 development board.
  • You should see the temperature, humidity, Heat index readings printed on the serial monitor.

Fig. 13: Readings observed from DHT11 sensor

Uploading DHT11 sensor reading to ThingSpeak Server

The IoT is the interconnection of physical objects or devices with sensors and software accessing capabilities to communicate data or information over the internet.

To build an IoT network, we need an interface medium that can fetch, control, and communicate data between sender and receiver electronics devices or servers.

Espressif Systems created the ESP32 Wi-Fi chip series. The ESP32 module is equipped with a 32-bit Tensilica microcontroller, 2.4GHz Wi-Fi connectivity, an antenna, memory, and power management modules, and much more. All of these built-in features of this ESP32 module make it ideal for IoT applications.

ThingSpeak web servie

It is an open data platform for the Internet of Things (Internet of Things). ThingSpeak is a MathWorks web service that allows us to send sensor readings/data to the cloud. We can also visualise and act on the data (calculate the data) sent to ThingSpeak by the devices. Data can be stored in both private and public channels.

ThingSpeak is commonly used for internet of things prototyping and proof of concept systems requiring analytics.

 

Getting Started with ThingSpeak

  • To create and account or log in to ThingSpeak (operated by MathWorks) server follow the link: https://thingspeak.com/
  • Click on Get Started for free.

Fig. 14: Getting started for free

  • Enter your details to create a MathWorks account as shown below:

Fig. 15: Create new account

  • If you have already created a MathWorks account, then click on Sign in.

Fig. 16: MathWorks Sign in

  • Create a channel on MathWorks server by clicking on the New Channel
  • ThingSpeak web service allows its user to create and save maximum of 4 channels for free.
  • If you are want access to more channels then you need to make payment for that.

Fig. 17: New Channel

  • Enter the respective details in the channel.

Fig. 18: Fill the channel details

  • Here we are creating two fields. First one represents the temperature and another one is to represent the humidity measured using DHT11 sensor. You can also add more fields as per your requirements.
  • A new URL containing the channel details and channel Stats will open, once you have successfully created the channel. On the same page/url, API keys are available for both read and write services.
  • Go to API Keys and copy the write API key and paste in your Arduino IDE code. So that ESP32 can send or write the DHT sensor readings to the MathWorks server.
  • In Private view your can also customize your chart. To edit the chart, click on the icon present on the top right corner of field chart.
  • Edit the details as per your requirements and click on the Save

Fig. 19: Field Chart Edit

 

Arduino IDE programming

Downloading and installing the required Library file:

    • Follow the link attached below to download the ThingSpeak Arduino library:

https://github.com/mathworks/thingspeak-arduino

  • Open the Arduino IDE.
  • Go to Sketch >> Include Library >> Add .ZIP Library and select the downloaded zip file.

Fig. 20: Adding ThingSpeak library

To check whether the library is successfully added or not:

  • Go to Sketch >> Include Library >> Manage Libraries

Fig. 21: manage libraries

  • Type thingspeak in the search bar.

Fig. 22: Arduino IDE Library manager.

  • The ThingSpeak library by MathWorks has been successfully downloaded.

Code

//------style guard ----

#ifdef __cplusplus

extern "C" {

#endif

uint8_t temprature_sens_read();

#ifdef __cplusplus

}

#endif

uint8_t temprature_sens_read();

// ------header files----

#include <WiFi.h>

#include "DHT.h"

#include "ThingSpeak.h"

//-----netwrok credentials

char* ssid = "replace this with your SSID"; //enter SSID

char* passphrase = "replace this with your password"; // enter the password

WiFiServer server(80);

WiFiClient client;

//-----ThingSpeak channel details

unsigned long myChannelNumber = 3;

const char * myWriteAPIKey = "replace this with your API key";

//----- Timer variables

unsigned long lastTime = 0;

unsigned long timerDelay = 1000;

//----DHT declarations

#define DHTPIN 4 // Digital pin connected to the DHT sensor

#define DHTTYPE DHT11 // DHT 11

// Initializing the DHT11 sensor.

DHT dht(DHTPIN, DHTTYPE);

 

void setup()

{

Serial.begin(115200); //Initialize serial

Serial.print("Connecting to ");

Serial.println(ssid);

WiFi.begin(ssid, passphrase);

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

}

// Print local IP address and start web server

Serial.println("");

Serial.println("WiFi connected.");

Serial.println("IP address: ");

Serial.println(WiFi.localIP());

server.begin();

//----nitialize dht11

dht.begin();

ThingSpeak.begin(client); // Initialize ThingSpeak

}

void loop()

{

if ((millis() - lastTime) > timerDelay)

{

delay(2500);

// Reading temperature or humidity takes about 250 milliseconds!

float h = dht.readHumidity();

// Read temperature as Celsius (the default)

float t = dht.readTemperature();

float f = dht.readTemperature(true);

if (isnan(h) || isnan(t) || isnan(f)) {

Serial.println(F("Failed to read from DHT sensor!"));

return;

}

Serial.print("Temperature (ºC): ");

Serial.print(t);

Serial.println("ºC");

Serial.print("Humidity");

Serial.println(h);

ThingSpeak.setField(1, h);

ThingSpeak.setField(2, t);

// Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different

// pieces of information in a channel. Here, we write to field 1.

int x = ThingSpeak.writeFields(myChannelNumber,

myWriteAPIKey);

if(x == 200){

Serial.println("Channel update successful.");

}

else{

Serial.println("Problem updating channel. HTTP error code " + String(x));

}

lastTime = millis();

}

}

Code Description

  • The style guards are used at the beginning of the program to declare some function to be of “C” linkage, instead of “C++” Basically, to allow C++ code to interface with C code.

Fig. 22: Style guard

  • Add the required header files. In this example we are using three libraries, Wi-Fi.h, DHT.h, ThingSpeak.
  • We have already discussed above how to download and add the DHT and ThingSpeak library files to Arduino IDE.

Fig. 23: Libraries

  • Enter the network credentials (SSID and Password) of the access point to which your ESP device is supposed to connect for internet connectivity.

Fig. 24

  • To access the created web server we also need to assign a port and usually port 80 is used for local web server.

Fig. 25: server port

  • A Wi-Fi client is created to connect with ThingSpeak.

Fig. 26

  • Global declaration of timer variables.

Fig. 27: Timer variables

  • Add the channel number and API (Write) Key. If you have created only one channel then the channel number will be ‘1’.

Fig. 28

Setup()

 
    • Initialize the Serial monitor with a 115200 baud rate for debugging purposes.

Fig. 29

  • Set ESP32 Wi-Fi module in station mode using mode() function.
  • Enable ESP32’s Wi-Fi module using begin() function which is passing two arguments SSID and password.
  • Wait until the ESP32 is not connected with the wifi network.

Fig. 30: connect to wifi

  • Once ESP32 is successfully connected to Wi-Fi network, the localIP() function will fetch the IP address of the device.
  • begin() function is used to initialize the server.

Fig.31: Fetch and print IP address

  • Initialize the ThingSpeak server using begin() function that is passing client (globally created) as an argument.

Fig. 32

  • Set the number of fields you have created to the ThingSpeak server. We are adding only two fields. First one represents the humidity measured by the sensor from its surrounding and the 2nd field represents the temperature in degree Celsius.
  • You can also add further fields like for temperature in Fahrenheit, heat index etc.
  • ThingSpeak allow the user to add up to maximum of 8 fields for different readings.

Fig. 33

  • writeFields() function is used to write data to the ThingSpeak server. This function is using the channel number and API key as an argument.

Fig. 34

  • Return the code 200 if the sensor readings are successfully published to ThingSpeak server and print the respective results on the serial monitor.

Fig. 35

Results

  • Copy the above code and paste it into your Arduino IDE.
  • Make the required changes in the above code and the changes required includes, network credentials (SSID and Password), API key, Channel number etc.
  • Compile and upload the above program into ESP32 development after selecting the correct development board and COM port.
  • Make sure the Access Point (Wi-Fi) is ON to which your ESP device is supposed to connect.
  • Open the serial monitor at a 115200 baud rate and press the EN button from the ESP32 development board.

Fig. 35: Results on the Serial monitor

  • Open the channel you have created on the ThingSpeak server.
  • You should see the charts updated with the latest temperature and humidity readings.

Fig. 36: Displaying humidity on thingSpeak server

Fig. 37: Displaying Temperature on ThingSpeak server

This concludes the tutorial. I hope you found this of some help and also hope to see you soon with new tutorial on ESP32.

Syed Zain Nasir

I am Syed Zain Nasir, the founder of <a href=https://www.TheEngineeringProjects.com/>The Engineering Projects</a> (TEP). I am a programmer since 2009 before that I just search things, make small projects and now I am sharing my knowledge through this platform.I also work as a freelancer and did many projects related to programming and electrical circuitry. <a href=https://plus.google.com/+SyedZainNasir/>My Google Profile+</a>

Share
Published by
Syed Zain Nasir