Categories
ESP32 ESP32-CAM

ESP32-CAM QR Reader with Next.js API

In our previous post we created a Next.js 14 API example code for QR code decoding. This simple esp32 QR code scanner example converts ESP32-cam image to base64 encoding and send to next.js API for QR code decoding. Now we are going to consume that API end point in our ESP32-CAM. The main challenges are that, how to capture the image? How to convert that image into the base64 encoding in Arduino environment? How to send that base64 encoded string to the API end point and do the detection? How to fetch the response and display the results. So, let’s do this step by step.

ESP32-CAM Image Capture

If you had seen the previous codes of the ESP32-CAM, the taking picture seems too much scary and there are lot of verbose. Fortunately, there is a library which tackle this problem and simplify the image capture process easy. There is object detection example on internet where the esp32-cam is used as ip camera and the python code is doing the object detection and displaying the results on laptop. That example use that library and make the image capture process easy. We will use that part of code but instead of serving the image as HTTP Server, we are doing the reverse thing which is to send that image to some remote server.

First download the library form GitHub. Install that library by putting the unzipped code under the Arduino -> Sketch -> Include Library -> Add .ZIP Library… -> Navigate to downloaded zip file -> add.

Once installed, now you are ready to capture the image in most easiest way.


#include <WiFi.h>
#include <esp32cam.h>

const char* WIFI_SSID = "project";
const char* WIFI_PASS = "project123";

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 easyCapture(){
auto frame = esp32cam::capture();
  if (!frame) {
    Serial.println("CAPTURE FAIL");
    return;
  }

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

}


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) {
    Serial.print('.');
    delay(500);
  }
  Serial.println("connected");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
  
  easyCapture();

}

void loop() {
  // put your main code here, to run repeatedly:

}
Code language: Arduino (arduino)

ESP32 Base64 Encoding of Image

Now it is time to convert the image to base64 encoding in our ESP32. You need to install the base64.h library for this purpose which could be used to convert the data to base64 encoding. In our case, we have to convert the image to base64 encoding and we are printing that to serial terminal which we later used to verify if the image is valid. Here is the code to convert the image to base64 and then printing to serial port.

#include <WebServer.h>
#include <WiFi.h>
#include <esp32cam.h>
#include "Base64.h"
const char* WIFI_SSID = "project";
const char* WIFI_PASS = "project123";

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 imageToBase64() {
  auto frame = esp32cam::capture();
  if (!frame) {
    Serial.println("CAPTURE FAIL");
    return;
  }

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

  // Encode image data to base64 (optional)
  String imageData = base64::encode((const uint8_t*)frame->data(), frame->size());

  Serial.println("");
  Serial.println(imageData);
}


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) {
    Serial.print('.');
    delay(500);
  }
  Serial.println("connected");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
  
  imageToBase64();


}

void loop() {
  // put your main code here, to run repeatedly:

}
Code language: Arduino (arduino)

This code will take an image on power reset, and convert it to base64 encoding and print that base64 string to serial terminal. You can copy that base64 string and use this online tool to view the base64 image . Here is the output in my case.

esp32 cam image to base64 encoding
esp32-cam base64 encoded image

API call with Base64 Encoded Image

Now that we are sure that our ESP32-CAM is working and capturing the images, and we also converted that image to base64 successfully. We are ready to send it to our Next.js API for QR code scanning from ESP32-CAM. For that, we can simply use the HTTP client to send data as POST request to the server. Here is the code for this.

#include <WiFi.h>
#include <esp32cam.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>

#include "Base64.h"
const char* WIFI_SSID = "project";
const char* WIFI_PASS = "project123";

static auto loRes = esp32cam::Resolution::find(320, 240);
static auto midRes = esp32cam::Resolution::find(350, 530);
static auto hiRes = esp32cam::Resolution::find(800, 600);

// The API endpoint
const char* serverName = "http://192.168.210.25:3000/api";

// Function to capture image and encode it in base64
String captureImageAndEncodeBase64() {
  auto frame = esp32cam::capture();
  if (!frame) {
    Serial.println("CAPTURE FAIL");
    return "";
  }

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

  // Encode image data to base64 (optional)
  String imageBase64 = base64::encode((const uint8_t*)frame->data(), frame->size());

  Serial.println("");
  Serial.println(imageBase64);
  
  return imageBase64;
}

// Function to send the base64 image to the API endpoint
void sendImageToAPI(String base64Image) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(serverName); // Specify the URL
    http.addHeader("Content-Type", "application/json");

    // Create the JSON object
    String jsonPayload = "{\"img\":\"" + base64Image + "\"}";

    // Send the request
    int httpResponseCode = http.POST(jsonPayload);
    
    // Check the response
    if (httpResponseCode > 0) {
      String response = http.getString();
      Serial.println(httpResponseCode);
      Serial.println(response);
    } else {
      Serial.print("Error on sending POST: ");
      Serial.println(httpResponseCode);
    }
    
    http.end(); // Free resources
  } else {
    Serial.println("WiFi Disconnected");
  }
}


// Function to connect to WiFi
void connectToWiFi() {
  Serial.print("Connecting to WiFi");
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("Connected to WiFi");
}


void sendImageToApi() {
  auto frame = esp32cam::capture();
  if (!frame) {
    Serial.println("CAPTURE FAIL");
    return;
  }

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

  // Encode image data to base64 (optional)
  String imageData = base64::encode((const uint8_t*)frame->data(), frame->size());

  Serial.println("");
  Serial.println(imageData);
}


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);
  connectToWiFi();
  Serial.println("connected");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
 // Capture and send the image
  String base64Image = captureImageAndEncodeBase64();
  if (base64Image != "") {
    sendImageToAPI(base64Image);
  }
  //sendImageToApi();


}

void loop() {
  // put your main code here, to run repeatedly:

}
Code language: Arduino (arduino)

Here is the result on the serial terminal.

esp32-cam image to base64 and qr-code decoding

As you can see we are successfully fetching the qr code result in our response.

By Abdul Rehman

My name is Abdul Rehman and I love to do Reasearch in Embedded Systems, Artificial Intelligence, Computer Vision and Engineering related fields. With 10+ years of experience in Research and Development field in Embedded systems I touched lot of technologies including Web development, and Mobile Application development. Now with the help of Social Presence, I like to share my knowledge and to document everything I learned and still learning.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.