ESP32-CAM Upload Foto ke Server (ESP32CAM Bootstrap 5 Gallery)
Hallo teman-teman sekalian, kebetulan saya lagi ada modul esp32cam. Kesempatan buat coba-coba dam mempelajari barang baru. oke langsung saja, pada case ini, kita akan melakukan upload data gambar hasil dari jepretan modul ESP32CAM ke server. Metodenya gimana nigh? mengingat processor esp yang lebih yahud untuk urusan IoT dan kapasitas memori, maka kita dapat menggunakan metode HTTP POST. Data yang dikirim ke server dengan POST disimpan di body dari struktur request HTTP.
Sebagaimana pada penggunaan di metode GET, pada metode POST ini kita juga memerlukan bantuan API. webAPI kita buat menggunakan program php (yang saya paham aja). Nah fungsi API ini nantinya digunakan untuk menampung data yang dikirim via metode POST kemudian diuraikan dan dicek. Apabila kondisinya memenuhi (dalam hal ini merupakan gambar yang valid) maka dilakukan proses penyimpanan file gambar tersebut di server. Ok langsung kita cus saja... ikuti langkah berikut
XAMPP Control panel
Jalankan service Apache dan MySQL (klik tombol start )
Pembuatan program web untuk Gallery display dan API
Ok, pertama kita akan buat API untuk proses upload file, kita siapkan dulu folder di direktori C:\xampp\htdocs . Kita siapkan folder dengan nama esp32cam_gallery
Masuk kedalam folder esp32cam_gallery yang telah dibuat. kemudian buat lagi folder dengan nama captured_images , folder ini nantinya digunakan untuk menyimpan gambar. File API upload_img.php akan mengakses folder ini untuk menympan data gambar yang telah diterima.Masih di dalam folder esp32cam_gallery, selanjutnya kita akan buat file dengan nama upload_img.php via notepad ++ , buka program notepad++ kemudian kopi paste program dibawah ini. selanjutnya simpan dengan nama upload_img.php di folder/direktori yang tadi kita buat (C:\xampp\htdocs\esp32cam_gallery)
<?php //based on PHP File Upload basic example https://www.w3schools.com/php/php_file_upload.asp date_default_timezone_set('Asia/Jakarta'); $target_dir = "captured_images/"; //folder untuk menyimpan gambar $date = new DateTime(); //this returns the current date time $date_string = $date->format('Y-m-d His'); $target_file = $target_dir . $date_string. basename($_FILES["imageFile"]["name"]); $uploadOk = 1; $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); $file_name = pathinfo($target_file,PATHINFO_BASENAME) ; // Check if image file is a actual image or fake image if(isset($_POST["imageFile"])) { $check = getimagesize($_FILES["imageFile"]["tmp_name"]); if($check !== false) { echo "File is an image - " . $check["mime"] . "."; $uploadOk = 1; } else { echo "File is not an image."; $uploadOk = 0; } } // Check if file already exists if (file_exists($target_file)) { echo "Sorry, file already exists."; $uploadOk = 0; } // Check file size if ($_FILES["imageFile"]["size"] > 500000) { echo "Sorry, your file is too large."; $uploadOk = 0; } // Allow certain file formats if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg" && $imageFileType != "gif" ) { echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed."; $uploadOk = 0; } // Check if $uploadOk is set to 0 by an error if ($uploadOk == 0) { echo "Sorry, your file was not uploaded."; // if everything is ok, try to upload file } else { if (move_uploaded_file($_FILES["imageFile"]["tmp_name"], $target_file)) { echo "Photo berhasil dipuload di server dengan nama " .$file_name; } else { echo "Sorry, Ada error dalam proses upload photo."; } } ?>
Selanjutnya kita buat file untuk melakukan testing upload gambar secara lokal dari komputer kita. Buat lembar baru dengan nama tester.php masukkan kode dibawah ini dan kemudian simpan di folder yang sama dengan file sebelumnya.
<!doctype html> <html lang="en"> <head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous" > </head> <body> <div class="container"> <div class="d-flex align-items-center" style="margin-top:15%;"> <div class="col-md6" style="padding:10px; border:2px solid black"> <h2>Test Upload manual</h2> <br> <form action="upload_img.php" method="post" enctype="multipart/form-data"> <div class="form-group"> <label for="image">Input Image</label> <input type="file" name="imageFile" id="imageFile"> </div> <br> <input type="submit" value="Upload Image" name="submit" class="btn btn-primary"> </form> </div> </div> </div> </body> </html>
Sebelum melangkah lebih jauh, mari kita coba apakah file API upload_img.php sudah berfungsi dengan baik.. akses file tester.php web browser di http://localhost/esp32cam_gallery/tester.php . Pilih gambar (bebas aja) kemudian klik upload image. Kalau berhasil akan muncul nitif seperti dibawah, selanjutnya dicek di folder captured_images apakah gembar benar-benar terupload atau boongan. nah apabila ada kendala sampai sini silahkan komen-komen...
Dengan berhasil test diatas maka dapat diasumsikan file upload_img.php sudah berfungsi dengan baik. selanjutnya kita akan buat halaman gallery yang digunakan untuk menampilkan hasil photo esp32cam nantinya. kita akan menggunakan framework Bootstrap 5 yang diakses secara CDN. buat file index.php dengan kode berikut ini
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>ESP32CAM Gallery Demo</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> </head> <body> <div class="container" style="padding-top:30px;"> <div class="d-flex justify-content-center" ><h1>ESP32CAM PHOTO Gallery</h1></div> <hr class="mt-2 mb-5"> <?php // Image extensions $image_extensions = array("png","jpg","jpeg","gif"); // Check delete HTTP GET request - remove images if(isset($_GET["delete"])){ $imageFileType = strtolower(pathinfo($_GET["delete"],PATHINFO_EXTENSION)); if (file_exists($_GET["delete"]) && ($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg") ) { unlink($_GET["delete"]); echo "<script> $(document).ready(function(){ $('#myModalOK').modal('show'); }); </script>"; } else { echo 'File not found - <a href="galeria.php">refresh</a>'; } } // Target directory $dir = 'captured_images/'; if (is_dir($dir)){ ?> <div class="row text-center text-lg-start"> <?php $count = 1; $files = scandir($dir); rsort($files); foreach ($files as $file) { if ($file != '.' && $file != '..') {?> <div class="col-lg-3 col-md-4 col-6" style="padding-bottom:30px;"> <div class="row"> <a href="<?php echo $dir . $file; ?>" class="d-block mb-4 h-100"> <img class="img-fluid img-thumbnail" src="<?php echo $dir . $file; ?>" alt=""> </a> </div> <div class="row justify-content-end"> <div class="col md-8"> <p><?php echo $file; ?></p> </div> <div class="col md-4"> <a href="index.php?delete=<?php echo $dir . $file; ?>" class="btn btn-danger btn-sm">Delete</a> </div> </div> </div> <?php $count++; } } if($count==1) { echo "<p>No images found</p>"; } } ?> </div> <!-- Modal Delete OK--> <div class="modal fade" id="myModalOK" tabindex="-1" aria-labelledby="myModalOKLabel" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header" style="background-color:#2cc791;"> <h5 class="modal-title" id="exampleModalLabel" style="color:white;">Success</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> Successfully delete image file <b><?php $path_parts = pathinfo($_GET["delete"],PATHINFO_BASENAME) ; echo $path_parts; ?> </b> </div> <div class="modal-footer"> <a class="btn btn-primary" href="index.php" role="button">OK</a> </div> </div> </div> </div> <!-- Modal Delete Not OK--> <div class="modal fade" id="myModalOK" tabindex="-1" aria-labelledby="myModalOKLabel" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header" style="background-color:#fc8403;"> <h5 class="modal-title" id="exampleModalLabel" style="color:white;">Success</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> Something wrong while deleting file <?php $path_parts = pathinfo($_GET["delete"],PATHINFO_BASENAME) ; echo $path_parts; ?> </div> <div class="modal-footer"> <a class="btn btn-secondary" href="galeria.php" role="button">OK</a> </div> </div> </div> </div> <div> </body> </html>
ok, semua file sudah dibuat, cek ulang struktur direktorinya (kalau ada yang kelewat). pastikan seperti berikut ya!
Program ESP32-CAM via arduino IDE
Ok, sebelum bermain-main dengan ESP microcontroller, pastikan kita telah menginstall boardnya terlebih dahulu. Nah untuk esp8266 dan esp32 itu beda ya untuk board nya yang di install di arduino IDE. hal ini merupakan hal dasar jd silahkan dipelajari di youtube atau tutorial lain
Nah peralatan/modul yang diperlukan
- Arduino IDE
- ESP32-CAM CAMERA OV2640 (cari di OL shop)
- Downloder program bisa menggunakan Dev Board USB to TTL CH340, atau menggunakan arduino uno, atau menggunakan downloader2 lainnya (USB serial TTL)
- wifi hotspot
#include <Arduino.h> #include <WiFi.h> #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "esp_camera.h" const char* ssid = "Android_AP"; const char* password = "YourWifiPassword"; 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); 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; //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(); 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); } }
3 komentar