Here are the two tutorials I'm basically following:
https://randomnerdtutorials.com/esp32-cam-save-picture-firebase-storage/#esp32-cam-send-pictures-firebase
https://randomnerdtutorials.com/esp32-cam-take-photo-display-web-server/
I wanted to take picture and send it to Firebase every 60 seconds.
I'm using ESP32CAM + OV5640, ESP32 Wrover Module board in Arduino IDE.
The problem I'm encountering is that after a first image-capture, the following image's quality got worsen, started to become grainy and getting greeny on the corner.
Here are a series of pictures I took:
Pic1:
Pic2:
Pic3:
And here is the code I'm working on:
/*********
Rui Santos
Complete instructions at: https://RandomNerdTutorials.com/esp32-cam-save-picture-firebase-storage/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Based on the example provided by the ESP Firebase Client Library
*********/
#include "Arduino.h"
#include "WiFi.h"
#include "esp_camera.h"
#include "soc/soc.h" // Disable brownout problems
#include "soc/rtc_cntl_reg.h" // Disable brownout problems
#include "driver/rtc_io.h"
#include <LittleFS.h>
#include <FS.h>
#include <Firebase_ESP_Client.h>
//Provide the token generation process info.
#include <addons/TokenHelper.h>
#include "credentials.h"
//Replace with your network credentials
const char* ssid = WIFI_SSID;
const char* password = WIFI_PASSWD;
// For example:
// #define STORAGE_BUCKET_ID "esp-iot-app.appspot.com"
// Photo File Name to save in LittleFS
#define FILE_PHOTO_PATH "/image.jpg"
#define BUCKET_PHOTO "/data/cam"
// OV2640 camera module pins (CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
boolean takeNewPhoto = true;
//Define Firebase Data objects
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig configF;
void fcsUploadCallback(FCS_UploadStatusInfo info);
bool uploadCompleted = false;
void initWiFi(){
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
}
void initLittleFS(){
if (!LittleFS.begin(true)) {
Serial.println("An Error has occurred while mounting LittleFS");
ESP.restart();
} else {
delay(500);
Serial.println("LittleFS mounted successfully");
}
}
void initCamera(){
// OV2640 camera module
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 = 10000000;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = CAMERA_GRAB_LATEST;
if (psramFound()) {
config.frame_size = FRAMESIZE_QSXGA;
// config.frame_size = FRAMESIZE_Q
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_QSXGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
}
// Capture Photo and Save it to LittleFS
void capturePhotoSaveLittleFS( void ) {
// Dispose first pictures because of bad quality
camera_fb_t* fb = NULL;
// Skip first 3 frames (increase/decrease number as needed).
for (int i = 0; i < 4; i++) {
fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
fb = NULL;
}
// Take a new photo
fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
delay(1000);
ESP.restart();
}
// Photo file name
Serial.printf("Picture file name: %s\n", FILE_PHOTO_PATH);
File file = LittleFS.open(FILE_PHOTO_PATH, FILE_WRITE);
// Insert the data in the photo file
if (!file) {
Serial.println("Failed to open file in writing mode");
} else {
file.write(fb->buf, fb->len); // payload (image), payload length
Serial.print("The picture has been saved in ");
Serial.print(FILE_PHOTO_PATH);
Serial.print(" - Size: ");
Serial.print(fb->len);
Serial.println(" bytes");
}
// Close the file
file.close();
esp_camera_fb_return(fb);
}
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
initWiFi();
initLittleFS();
// Turn-off the 'brownout detector'
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
initCamera();
//Firebase
// Assign the api key
configF.api_key = API_KEY;
//Assign the user sign in credentials
auth.user.email = USER_EMAIL;
auth.user.password = USER_PASSWORD;
//Assign the callback function for the long running token generation task
configF.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h
Firebase.begin(&configF, &auth);
Firebase.reconnectWiFi(true);
}
void loop() {
static int counter = 0;
if (takeNewPhoto) {
capturePhotoSaveLittleFS();
takeNewPhoto = false;
}
delay(1000);
if (Firebase.ready() && !uploadCompleted){
uploadCompleted = true;
Serial.print("Uploading picture... ");
//MIME type should be valid to avoid the download problem.
//The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h.
if (Firebase.Storage.upload(&fbdo, STORAGE_BUCKET_ID /* Firebase Storage bucket id */, FILE_PHOTO_PATH /* path to local file */, mem_storage_type_flash /* memory storage type, mem_storage_type_flash and mem_storage_type_sd */, BUCKET_PHOTO + String(counter++) + ".jpg" /* path of remote file stored in the bucket */, "image/jpeg" /* mime type */, fcsUploadCallback)){
Serial.printf("\nDownload URL: %s\n", fbdo.downloadURL().c_str());
}else{
Serial.println(fbdo.errorReason());
}
}
delay(60000);
takeNewPhoto = true;
uploadCompleted = false;
}
// The Firebase Storage upload callback function
void fcsUploadCallback(FCS_UploadStatusInfo info){
if (info.status == firebase_fcs_upload_status_init){
Serial.printf("Uploading file %s (%d) to %s\n", info.localFileName.c_str(), info.fileSize, info.remoteFileName.c_str());
}
else if (info.status == firebase_fcs_upload_status_upload)
{
Serial.printf("Uploaded %d%s, Elapsed time %d ms\n", (int)info.progress, "%", info.elapsedTime);
}
else if (info.status == firebase_fcs_upload_status_complete)
{
Serial.println("Upload completed\n");
FileMetaInfo meta = fbdo.metaData();
Serial.printf("Name: %s\n", meta.name.c_str());
Serial.printf("Bucket: %s\n", meta.bucket.c_str());
Serial.printf("contentType: %s\n", meta.contentType.c_str());
Serial.printf("Size: %d\n", meta.size);
Serial.printf("Generation: %lu\n", meta.generation);
Serial.printf("Metageneration: %lu\n", meta.metageneration);
Serial.printf("ETag: %s\n", meta.etag.c_str());
Serial.printf("CRC32: %s\n", meta.crc32.c_str());
Serial.printf("Tokens: %s\n", meta.downloadTokens.c_str());
Serial.printf("Download URL: %s\n\n", fbdo.downloadURL().c_str());
}
else if (info.status == firebase_fcs_upload_status_error){
Serial.printf("Upload failed, %s\n", info.errorMsg.c_str());
}
}
I'm assuming it has something to do with the buffer of the local file system? So I did try to do camera initialization/ESP restart in the loop section however none of them worked.
And I've also read this issue posted on Github discussing some similar problem, but the configuring terms are a bit overwhelming to me, still working on finding a working configuration setting.
https://github.com/espressif/esp32-camera/issues/314
Any suggestions are welcome, thank you!
(I'm pretty new to arduino so if I'm missing some important setting info like version numbers or something else please let me know!)