Mengakses Lampu Flash di ESP32-CAM

Pada modul ESP32-CAM sudah terpasang flash light yang menggunakan led super bright warna putih. Keberadaan lampu ini biasanya jarang diperhatikan, tetapi lampu ini juga merupakan fitur yang mungkin sedikit membatu penerangan saat dalam proses mengambil gambar.  

Dimana itu FlashLight

ESP32-CAM memiliki LED internal yang sangat terang yang dapat berfungsi sebagai lampu flash saat mengambil foto. LED ini terhubung secara internal ke GPIO 4. Perlu diperhatikan bahwa GPIO4 juga terhubung dengan DATA1 pada slot microSD. Artinya saat sedang menggunakan microSD sebaiknya jangan menggunakan fungsi Flash Light ini karena akan berpengaruh pada kunfigurasi pin pada GPIO4.

esp32-cam flash light control

Testing dengan Blink

Untuk membuktikan bahwa led FlashLight ini dapat diakses melalui GPIO4, mari kita test menggunakan program Blink.

int LED_FLASHLIGHT = 4;
void setup() {
  pinMode(LED_FLASHLIGHT, OUTPUT);
}

void loop() {
  digitalWrite(LED_FLASHLIGHT, HIGH);  
  delay(1000);                       
  digitalWrite(LED_FLASHLIGHT, LOW);   
  delay(1000);                       
}

Upload program diatas ke ESP32-CAM dan kira-kira begini hasilnya

menyalakan lampu flash esp32-cam

Implementasi dalam proses pengambilan gambar

Ok, program diatas hanya contoh untuk control nyala flsh light secara umum dan sederhana. nah sekarang bagaimana caranya untuk implementasi nyala flashlight pada saat pengambilan gambar?
Secara berurutan, maka kurang lebih seperti ini: flash on >> Capture image >> flash off. 
Mari kita implementasikan pada program pengambilan gambar gallery seperti tutorial sebelumnya. Silahkan teman-teman menuju tutorial disini untuk pengantar dari program yang akan kita buat dibawah ini.

Program ESP32CAM Upload Foto ke Server dengan fungsi flash light

#include <Arduino.h>
#include <WiFi.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"

#define FlashLed 4
const char* ssid = "Android_AP";       //wifi hostpot
const char* password = "Rahasiadong";  //password wifi

String serverName = "192.168.1.4";     //alamat server  
String serverPath = "/esp32cam_gallery/upload_img.php";     
const int serverPort = 80;

WiFiClient client;

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

const int Interval = 30000;    // proses pengambilan photo interval 30 detik
unsigned long previousMillis = 0; 
String jsonres;

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); 
  Serial.begin(115200);
  pinMode(FlashLed, OUTPUT); digitalWrite(FlashLed, LOW); 
  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);  
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("ESP32-CAM IP Address: ");
  Serial.println(WiFi.localIP());

  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;

  // init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_VGA;
    config.jpeg_quality = 12;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 8;  //0-63 lower number means higher quality
    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);
    delay(1000);
    ESP.restart();
  }

  sensor_t * s = esp_camera_sensor_get();
  s->set_framesize(s, FRAMESIZE_SVGA); //UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= Interval) {
    Serial.println("Bersiap kirim foto ke server..");
    sendPhoto();
    previousMillis = currentMillis;
  }
}

void sendPhoto() {
  String AllData;
  String DataBody;
  digitalWrite(FlashLed, HIGH);  //aktifkan flash light
  //pre capture for accurate timing
  for (int i = 0; i <= 3; i++) {
    camera_fb_t * fb = NULL;
    fb = esp_camera_fb_get();
     if(!fb) {
        Serial.println("Camera capture failed");
        delay(1000);
        ESP.restart();
        return;
      } 
    esp_camera_fb_return(fb);
    delay(200);
  }
  
  camera_fb_t * fb = NULL;
  fb = esp_camera_fb_get();
  
  digitalWrite(FlashLed, LOW); //nonaktifkan flash light
  
  Serial.println("Connecting to server: " + serverName);

  if (client.connect(serverName.c_str(), serverPort)) {
    Serial.println("Connection successful!");   
     
    String post_data = "--dataMarker\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"_esp32Photo.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
    String head =  post_data;
    String boundary = "\r\n--dataMarker--\r\n";
    //Serial.println(head);
    uint32_t imageLen = fb->len;
    uint32_t dataLen = head.length() + boundary.length();
    uint32_t totalLen = imageLen + dataLen;
    
    client.println("POST " + serverPath + " HTTP/1.1");
    client.println("Host: " + serverName);
    client.println("Content-Length: " + String(totalLen));
    client.println("Content-Type: multipart/form-data; boundary=dataMarker");
    client.println();
    client.print(head);
  
    uint8_t *fbBuf = fb->buf;
    size_t fbLen = fb->len;
    //Serial.println(fbLen);
    for (size_t n=0; n<fbLen; n=n+1024) {
      if (n+1024 < fbLen) {
        client.write(fbBuf, 1024);
        fbBuf += 1024;
      }
      else if (fbLen%1024>0) {
        size_t remainder = fbLen%1024;
        client.write(fbBuf, remainder);
      }
    }   
    client.print(boundary);
    
    esp_camera_fb_return(fb);
   
    int timoutTimer = 10000;
    long startTimer = millis();
    boolean state = false;
    Serial.println("Response:");
    while ((startTimer + timoutTimer) > millis()) {
      Serial.print(".");
      delay(200);
         
      // Skip HTTP headers   
      while (client.available()) {
        char c = client.read();
        if (c == '\n') {
          if (AllData.length()==0) { state=true; }
          AllData = "";
        }
        else if (c != '\r') { AllData += String(c); }
        if (state==true) { DataBody += String(c); }
        startTimer = millis();
      }
      if (DataBody.length()>0) { break; }
    }
    client.stop();
    Serial.println(DataBody);
    Serial.println("##############");
    Serial.println();
    
  }
  else {
    DataBody = "Connection to " + serverName +  " failed.";
    Serial.println(DataBody);
  }
}

Bagaimana teman-teman? apakah ada perbedaan yang signifikaan saat menggunakan flashlight? coba deh komen-komen dan spil hasilny. Selamat mencoba !