ESP32 Projects

I’m doing a couple of ESP32 projects because I want to get to know the device. Some code is hard to find or doesn’t work so here I share it.

If you want me to build an ESP-32 application for you email at frits@rincker.nl

I use the ESP32-Wroom module and the ESP32-CAM module from AI-tinker.

Make sure your power supply is stabile, so direct USB connection to your computer, not via a hub. Also add delays if you think the process crashes due to power draw issues.

ESP32-CAM

A simple function of the ESP32-CAM module that is for sale in Holland is to make pictures and store them on the Micro-SD card. This is often done with a time function to add a date but that’s not included here. This code will save the images in the root dir of the SD, with numbers (counter) that run up. If you restart the module it will start again at 0 and overwrite previous images. You can set the time between images with the delay in the loop part.

#include <eloquent_esp32cam.h>
#include <eloquent_esp32cam/extra/esp32/fs/sdmmc.h>
#include "SD_MMC.h" 
#include "FS.h" 

using namespace eloq;

int counter;

// Function to write the image file to the SD card
void writeFile(fs::FS &fs, const char * path, const uint8_t * data, size_t length){
    Serial.printf("Writing file: %s\n", path);

    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }

    if(file.write(data, length)){
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
    file.close();
}

void setupSSD() {
    if(!SD_MMC.begin()){
        Serial.println("Card Mount Failed");
        return;
    }

    uint8_t cardType = SD_MMC.cardType();

    if(cardType == CARD_NONE){
        Serial.println("No SD_MMC card attached");
        return;
    }

    Serial.print("SD_MMC Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
    Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
    Serial.printf("\n\n\n");
}

void setup() {
    delay(3000);
    Serial.begin(115200);
    setupSSD();
    // camera settings
    // replace with your own model!
    camera.pinout.aithinker();
    camera.brownout.disable();
    camera.resolution.vga();
    camera.quality.high();

    // init camera
    while (!camera.begin().isOk())
        Serial.println(camera.exception.toString());
    Serial.println("Camera OK");
}

void loop() {
    if (!camera.capture().isOk()) {
        Serial.println(camera.exception.toString());
        return;
    } else { 
        Serial.println("Capturing Image");
    }

    
    String path = "/picture";
    path += counter;
    path +=".jpg";

    writeFile(SD_MMC, path.c_str(), camera.frame->buf, camera.frame->len);
    
    delay(3000); // Capture image every 10 seconds
    
    counter++;
}

ESP32 Wifi Config

This is code to have the ESP32 module log in to to set the Wifi and that then will log into the Wifi itself. You can use this if you want to set up the module as a sensor that talks to a server, if you want to use the ESP32-CAM module that you want to post pictures via your Wifi network. This code stores the password in the eprom memory and if it doesn’t find any credentials that work it will ask for ‘network id/password’ in a dialog. I have not figured out how to make it captive on my mobile phone, but it does direct to the configuration page when you log in with your laptop or PC.

Then if you are logged in the Wifi network it will do a POST to a website.

#include <FS.h>                   //this needs to be first, or it all crashes and burns...

#include <WiFi.h>          //https://github.com/esp8266/Arduino

//needed for library
#include <DNSServer.h>
#include <WebServer.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <HTTPClient.h>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println();

  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;

  //exit after config instead of connecting
  //wifiManager.setBreakAfterConfig(true);

  //reset settings - for testing
  //wifiManager.resetSettings();


  //tries to connect to last known settings
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP" with password "password"
  //and goes into a blocking loop awaiting configuration
  if (!wifiManager.autoConnect("AutoConnectAP", "password")) {
    Serial.println("failed to connect, we should reset as see if it connects");
    delay(3000);
    ESP.restart();
    delay(5000);
  }

  //if you get here you have connected to the WiFi
  Serial.println("connected...yeey :)");


  Serial.println("local ip");
  Serial.println(WiFi.localIP());
}

void loop() {
  Serial.println("In the loop");
  Serial.println(WiFi.localIP());
  // put your main code here, to run repeatedly:
   // Perform HTTP POST request
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    
    http.begin("http://www.website.com/esp32/index.php"); // Specify the URL
    http.addHeader("Content-Type", "application/x-www-form-urlencoded"); // Specify content-type header

    String postData = "temp=32&banana=yellow"; // Data to send in the post request
    int httpCode = http.POST(postData); // Make the request

    if (httpCode > 0) { // Check for the returning code
      String payload = http.getString();
      Serial.println(httpCode);  // Print HTTP return code
      Serial.println(payload);   // Print the request response payload
    } else {
      Serial.println("Error on HTTP request");
    }
    
    http.end(); // Free resources
  } else {
    Serial.println("WiFi not connected");
  }

}

The server side code is very simple (PHP stack index.php)

<?php

echo var_dump($_POST);

echo var_dump($_GET);

The comments are by the original author, I publish it because this code 100% works so it saves some time. Make sure you have the right libraries and if it gives an error that there are several just go into the library manager and uninstall the ones you don’t need.

ESP32-CAM Upload

The following script posts an image from an ESP32-cam to a website. The script also provides a Wifi config interaction, but the way the script is written now you need to re-enter the wifi credentials every time you power up the module. To fix this there need to be a button press or something added, but the used USB programmer doesn’t have space for buttons, a bit of a waste.

The ESP32 code just posts the image data to the URL

#include <eloquent_esp32cam.h>
#include <eloquent_esp32cam/extra/esp32/fs/sdmmc.h>
#include "SD_MMC.h" 
#include "FS.h" 
#include <WiFi.h>
#include <DNSServer.h>
#include <WebServer.h>
#include <WiFiManager.h>
#include <HTTPClient.h>

using namespace eloq;

int counter = 0;
const char *post_url = "http://www.website.com/index.php";

void setup() {
    Serial.begin(115200);
    delay(3000); // Allow time for serial monitor to start

    // Initialize SD card
    if (!SD_MMC.begin()) {
        Serial.println("SD Card Mount Failed");
        return;
    }

    // Print SD card type and size
    uint8_t cardType = SD_MMC.cardType();
    if (cardType == CARD_NONE) {
        Serial.println("No SD_MMC card attached");
        return;
    }
    Serial.print("SD_MMC Card Type: ");
    switch (cardType) {
        case CARD_MMC: Serial.println("MMC"); break;
        case CARD_SD: Serial.println("SDSC"); break;
        case CARD_SDHC: Serial.println("SDHC"); break;
        default: Serial.println("UNKNOWN"); break;
    }
    uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
    Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);

    // Camera settings
    camera.pinout.aithinker();
    camera.brownout.disable();
    camera.resolution.vga();
    camera.quality.high();

    // Initialize camera
    while (!camera.begin().isOk()) {
        Serial.println(camera.exception.toString());
        delay(1000);
    }
    Serial.println("Camera OK");

    delay(3000);
    // Initialize WiFi
    WiFiManager wifiManager;

    //reset settings - for testing
    wifiManager.resetSettings();
     
    delay(3000);

    if (!wifiManager.autoConnect("AutoConnectAP", "password")) {
        Serial.println("Failed to connect to WiFi, resetting...");
        delay(3000);
        ESP.restart();
    }
    Serial.println("Connected to WiFi");
}

void loop() {
    if (!camera.capture().isOk()) {
        Serial.println(camera.exception.toString());
        return;
    } else {
        Serial.println("Capturing Image");
    }

    String path = "/picture" + String(counter) + ".jpg";
    writeFile(SD_MMC, path.c_str(), camera.frame->buf, camera.frame->len);

    // HTTP POST
    HTTPClient http;
    http.begin(post_url);
    http.addHeader("Content-Type", "application/octet-stream");

    int httpCode = http.POST(camera.frame->buf, camera.frame->len);
    if (httpCode > 0) {
        Serial.printf("[HTTP] POST... code: %d\n", httpCode);
        if (httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            Serial.println(payload);
        }
    } else {
        Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }

    http.end();
    delay(10000); // Capture image every 10 seconds
    counter++;
}

void writeFile(fs::FS &fs, const char * path, const uint8_t * data, size_t length) {
    Serial.printf("Writing file: %s\n", path);

    File file = fs.open(path, FILE_WRITE);
    if (!file) {
        Serial.println("Failed to open file for writing");
        return;
    }

    if (file.write(data, length)) {
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
    file.close();
}

On the server side you have the above script uploaded (as index.php), and an images directory where the index.php is located. As is the image file name will not be chronological so one could call it time() with some added text or identifier or even format a date to save it.

<?php

// Define the directory to save images
$target_dir = "images/";

// Ensure the directory exists
if (!is_dir($target_dir)) {
    mkdir($target_dir, 0777, true);
}

// Generate a unique file name
$target_file = $target_dir . uniqid() . ".jpg";

// Read the raw POST data
$image_data = file_get_contents('php://input');

if ($image_data) {
    // Write the image data to a file
    if (file_put_contents($target_file, $image_data)) {
        echo "File uploaded successfully: " . $target_file;
    } else {
        echo "Failed to write file.";
    }
} else {
    echo "No data received.";
}

This will place the images in the /images folder for download or further analysis.