ESPCam32-ส่งภาพขึ้น Server ก่อนเล่นสตรีมมิ่ง

วันนี้ยังคงเล่น ESPCam32 กันต่อ  โดยเน้นการส่งรูปขึ้น Server โดยจะแบ่งเป็น 2 ตอน  คือ  (1) ส่งไปทุก ๆ  30 วินาที  และ (2) ส่งเมื่อมีการเคลื่นไหวผ่านหน้ากล้อง
วัตถุประสงค์

  1. เรียนรู้การถ่ายภาพลง Server
  2. เรียนรู้การสร้าง  Sensor จับความเคลื่อนไหวและถ่ายภาพส่งไปยังระบบ Server

องค์ประกอบ

  1. ESPCam32
  2. กล่องบรรจุ พร้อม สาย USB

  จากตอนก่อนหน้า
 แบบแยกส่วน
  ชุดแรกเลยเพื่อให้ใช้การได้ก่อน

ปรับปรุงการจัดวาง  นำเอาบอร์ด TTL  วางไว้ใต้บอร์ด ESPCam32 ให้มีระยะปลอดภัยและไม่มีปัญหาเรื่องความร้อน  เพื่อให้สามารถบรรจุกล่องขนาดกระทัดรัดได้

ผลงานการประกอบในรูปแบบขนาดแตกต่างกัน
 
 ตำแหน่งติดตั้งชั่วคราวกับกระจก
การต่อวงจร ก็เหมือนครั้งก่อน  เรียกว่าเอาชุดเดิมมาทดสอบฟังก์ชั่นใหม่กัน  โดยเราก็ลงโค้ดกันได้เลย  แก้ไขก็เฉพาะ ssid และ password  และต้องขอบคุณเจ้าของโค้ด  ตามลิงก์นี้เลย
และทำการดาวน์โหลดโค้ดจาก  github ในส่วนของ timelapseserver  
 

#include "esp_http_client.h"
#include "esp_camera.h"
#include <WiFi.h>
#include "Arduino.h"
const char* ssid = "Arsenal2019_2.4G";
const char* password = "xxxxxxxxx";
int capture_interval = 20000; // Microseconds between captures
const char *post_url = "https://xxxx.samongiot.com/getcam32.php"; // Location where images are POSTED
bool internet_connected = false;
long current_millis;
long last_capture_millis = 0;
// 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
void setup()
{
  Serial.begin(115200);
  if (init_wifi()) { // Connected to WiFi
    internet_connected = true;
    Serial.println("Internet connected");
  }
  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_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } 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);
    return;
  }
}
bool init_wifi()
{
  int connAttempts = 0;
  Serial.println("\r\nConnecting to: " + String(ssid));
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED ) {
    delay(500);
    Serial.print(".");
    if (connAttempts > 10) return false;
    connAttempts++;
  }
  return true;
}
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
  switch (evt->event_id) {
    case HTTP_EVENT_ERROR:
      Serial.println("HTTP_EVENT_ERROR");
      break;
    case HTTP_EVENT_ON_CONNECTED:
      Serial.println("HTTP_EVENT_ON_CONNECTED");
      break;
    case HTTP_EVENT_HEADER_SENT:
      Serial.println("HTTP_EVENT_HEADER_SENT");
      break;
    case HTTP_EVENT_ON_HEADER:
      Serial.println();
      Serial.printf("HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
      break;
    case HTTP_EVENT_ON_DATA:
      Serial.println();
      Serial.printf("HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
      if (!esp_http_client_is_chunked_response(evt->client)) {
        // Write out data
        // printf("%.*s", evt->data_len, (char*)evt->data);
      }
      break;
    case HTTP_EVENT_ON_FINISH:
      Serial.println("");
      Serial.println("HTTP_EVENT_ON_FINISH");
      break;
    case HTTP_EVENT_DISCONNECTED:
      Serial.println("HTTP_EVENT_DISCONNECTED");
      break;
  }
  return ESP_OK;
}
static esp_err_t take_send_photo()
{
  Serial.println("Taking picture...");
  camera_fb_t * fb = NULL;
  esp_err_t res = ESP_OK;
  fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return ESP_FAIL;
  }
  esp_http_client_handle_t http_client;
  esp_http_client_config_t config_client = {0};
  config_client.url = post_url;
  config_client.event_handler = _http_event_handler;
  config_client.method = HTTP_METHOD_POST;
  http_client = esp_http_client_init(&config_client);
  esp_http_client_set_post_field(http_client, (const char *)fb->buf, fb->len);
  esp_http_client_set_header(http_client, "Content-Type", "image/jpg");
  esp_err_t err = esp_http_client_perform(http_client);
  if (err == ESP_OK) {
    Serial.print("esp_http_client_get_status_code: ");
    Serial.println(esp_http_client_get_status_code(http_client));
  }
  esp_http_client_cleanup(http_client);
  esp_camera_fb_return(fb);
}
void loop()
{
  // TODO check Wifi and reconnect if needed
  current_millis = millis();
  if (current_millis - last_capture_millis > capture_interval) { // Take another picture
    last_capture_millis = millis();
    take_send_photo();
  }
}

โดยในส่วนของ server นั้นให้ทำการสร้าง  folder  timelapse  และสร้าง  code php ไว้ใน  folder เดียวกันกับ timelapse

<?php
$received = file_get_contents('php://input');
$fileToWrite = "timelapse/upload - ".time().".jpg";
file_put_contents($fileToWrite, $received);
?>


เมื่อเปิดระบบให้กล้องทำงาน  มันจะทำการเชื่อมต่อกับ WiFi และส่งภาพขึ้นไปเก็บใน server ที่เรากำหนดไว้ในโค้ด

จากนั้นก็เป็นการพัฒนาแอพพลิเคชั่นมาเพื่อเปิดดูไฟล์ภาพ
ถึงขณะนี้หากปล่อยให้ระบบทำการส่งภาพขึ้นไปเก็บ  ทุก ๆ 30 วินาที  ไม่นาน server ก็คงจะเต็ม   ดังนั้นเราจึงต้องพัฒนาต่อไปเพื่อให้กล้องทำการส่งภาพมาเฉพาะที่มีความเคลื่อนไหว  หรือ ให้ทำการ streaming  โดยเก็บภาพไว้แบบจำกัดเวลา  ในโอกาสต่อไป