ESP32 CAM Firebase Timestamp on Photo

Hi,
I already tried this in the german Section with the conclusion, that I linked a website wrong. Therefore im trying it in english now.
I am trying to make a little instant camera with a esp32 CAM (and a tiny printer, but not the problem at the moment). I was trying to use the code from this "tutorial": Tutorial save on Firebase. That works fantastic, but it is only able to save a single photo. So I tried to include the Timestamp part from this "tutorial": Tutorial Timestamp. Sadly I have no experience in Programming and dont understand, why it wont work.
I would be happy for any help.

Lucas

PS: if you want to see, what I tried I can provide the code. xD

The forum members expect you to post the code. For instructions, please read the "How to get the best out of this forum" post.

Also, you need to explain what you expected to happen, and what happened instead.

Okay, can do.

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

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

// Insert Firebase project API Key
#define API_KEY "REPLACE_WITH_YOUR_FIREBASE_PROJECT_API_KEY"

// Insert Authorized Email and Corresponding Password
#define USER_EMAIL "REPLACE_WITH_THE_AUTHORIZED_USER_EMAIL"
#define USER_PASSWORD "REPLACE_WITH_THE_AUTHORIZED_USER_PASSWORD"

// Insert Firebase storage bucket ID e.g bucket-name.appspot.com
#define STORAGE_BUCKET_ID "REPLACE_WITH_YOUR_STORAGE_BUCKET_ID"
// For example:
//#define STORAGE_BUCKET_ID "esp-iot-app.appspot.com"


//here begins the  integrated part

// Connect to wifi
void  initWiFi(){
  WiFi.begin(ssid, password);
  Serial.println("Connecting Wifi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
}

// Function to set timezone
void setTimezone(String timezone){
  Serial.printf("  Setting Timezone to %s\n",timezone.c_str());
  setenv("TZ",timezone.c_str(),1);  //  Now adjust the TZ.  Clock settings are adjusted to show the new local time
  tzset();
}

// Connect to NTP server and adjust timezone
void initTime(String timezone){
  struct tm timeinfo;
  Serial.println("Setting up time");
  configTime(0, 0, "pool.ntp.org");    // First connect to NTP server, with 0 TZ offset
  if(!getLocalTime(&timeinfo)){
    Serial.println(" Failed to obtain time");
    return;
  }
  Serial.println("Got the time from NTP");
  // Now we can set the real timezone
  setTimezone(timezone);
}

// Get the picture filename based on the current ime
String getPictureFilename(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return "";
  }
  char timeString[20];
  strftime(timeString, sizeof(timeString), "%Y-%m-%d_%H-%M-%S", &timeinfo);
  Serial.println(timeString);
  String filename = "/picture_" + String(timeString) +".jpg";
  return filename; 
}

//I modified this part
// Photo File Name to save in LittleFS
//#define FILE_PHOTO_PATH "/photo.jpg"
//#define BUCKET_PHOTO "/data/photo.jpg"

// Photo File Name to save in LittleFS
#define FILE_PHOTO_PATH String filename
#define BUCKET_PHOTO String filename


// 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 taskCompleted = false;

// 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 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 = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.grab_mode = CAMERA_GRAB_LATEST;

  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 1;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    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();
  } 
}

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() {
  if (takeNewPhoto) {
    capturePhotoSaveLittleFS();
    takeNewPhoto = false;
  }
  delay(1);
  if (Firebase.ready() && !taskCompleted){
    taskCompleted = 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 /* 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());
    }
  }
}

// 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 expectet do get a timestamp in my photos. What happend was that apparantly the "String Filename" wasn't defined.
(yes I put my network credentials and Firebase things in, just didnt put them in in here)

Post the complete error message.

If in line 93 & 94 is String filename, then the error message is:

C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino: In function 'void capturePhotoSaveLittleFS()':
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: error: expected primary-expression before 'filename'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: error: expected primary-expression before 'filename'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: error: expected primary-expression before 'filename'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino: At global scope:
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:167:6: error: redefinition of 'void initWiFi()'
 void initWiFi(){
      ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:43:7: note: 'void initWiFi()' previously defined here
 void  initWiFi(){
       ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino: In function 'void loop()':
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: error: expected primary-expression before 'filename'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:32: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH String filename
                                ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:94:29: error: expected primary-expression before 'filename'
 #define BUCKET_PHOTO String filename
                             ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:94:29: note: in definition of macro 'BUCKET_PHOTO'
 #define BUCKET_PHOTO String filename
                             ^~~~~~~~
Multiple libraries were found for "SD.h"
  Used: C:\Users\Admin\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.14\libraries\SD
  Not used: C:\Users\Admin\AppData\Local\Arduino15\libraries\SD
exit status 1

Compilation error: expected primary-expression before 'filename'

If in Line 93 & 94 is only filename the error message is:

C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino: In function 'void capturePhotoSaveLittleFS()':
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: error: 'filename' was not declared in this scope
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: note: suggested alternative: 'basename'
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino: At global scope:
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:167:6: error: redefinition of 'void initWiFi()'
 void initWiFi(){
      ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:43:7: note: 'void initWiFi()' previously defined here
 void  initWiFi(){
       ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino: In function 'void loop()':
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: error: 'filename' was not declared in this scope
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: note: suggested alternative: 'basename'
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
C:\Users\Admin\Documents\Arduino\Timestamp_fail\Timestamp_fail.ino:93:25: note: in definition of macro 'FILE_PHOTO_PATH'
 #define FILE_PHOTO_PATH filename
                         ^~~~~~~~
Multiple libraries were found for "SD.h"
  Used: C:\Users\Admin\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.14\libraries\SD
  Not used: C:\Users\Admin\AppData\Local\Arduino15\libraries\SD
exit status 1

Compilation error: 'filename' was not declared in this scope

If the following is your modification to the code, it won't work.

"#define" acts as text substitution into the source code. The compiler merely replaces FILE_PHOTO_PATH with whatever text follows it in the #define

It is not possible to replace a file name with a variable declaration, such as String filename.

//I modified this part
// Photo File Name to save in LittleFS
//#define FILE_PHOTO_PATH "/photo.jpg"
//#define BUCKET_PHOTO "/data/photo.jpg"

// Photo File Name to save in LittleFS
#define FILE_PHOTO_PATH String filename
#define BUCKET_PHOTO String filename

Assuming you want to open a file with a name that is set elsewhere in the code, where and how will that file name be set?

Thanks, but i know that it doesn't work, thats why im here and asking how I would have to do it to make it work. Again, I know nothing about Programming.

Start with the unmodified program and if it compiles and runs, learn how it works.

It is not clear from the original post what you are actually trying to do.

okay, i already tried that,it runs as it is, and I'm trying to use, what the program does. Meaning I want to take a picture if the esp32 gets a reset. The Problem I had with the Program was, that it only saves one Picture in the Firebase, which is then named "photo.jpg". Therefor I tried to implement the Timestamp from the other code in that code (at least where I thought where it belonged). I also tried a few other thing, that didnt work (didn't save them).

And the learning how it runs is my problem. Because as I understood it the

// Photo File Name to save in LittleFS
#define FILE_PHOTO_PATH "/photo.jpg"
#define BUCKET_PHOTO "/data/photo.jpg"

is where the name is "made" (I also confirmed that by chamging the "photo.jpg" part.

my problem is now, that I dont know how to make that part vary for different photos.

Alternativly if you dont want to help or can't help me, is there a good forum you could recommend?

If you don't have any idea how to program an Arduino, this is a very poor choice for a starting project-- you are jumping in way over your head.

If you don't want to take the time to learn, you can hire someone to write code for you by posting on the Jobs and Paid Collaboration forum section.

That said, it is not difficult for someone who has taken the time to learn basic programming skills to implement successive file names. Instead of this:

  Serial.printf("Picture file name: %s\n", FILE_PHOTO_PATH);
  File file = LittleFS.open(FILE_PHOTO_PATH, FILE_WRITE);

something like this should work:

  static int file_number = 0;  //incremented for each photo
  char filename_buf[40]={0}; //base file path/name
  snprintf(filename_buf,sizeof(filename_buf),"/photo%02d.jpg",file_number++);
  Serial.printf("Picture file name: %s\n", filename_buf);
  File file = LittleFS.open(filename_buf, FILE_WRITE);