見出し画像

ESP32-CAMで撮影した画像ををLINE notifyに転送する

ESP32で撮影した画像をLINEnotifyで確認できるようにしてみます。💪

1、システムの概要

接続のイメージはこんな感じです。

スクリーンショット 2021-02-15 21.41.46

ESP32-CAMはHTTP serverとして動作させます。記載していませんが、ESP32-CAM、RaspberryPiはルーターを使ってwifiで接続しています。RaspberryPiはルータをゲートウェイとしてインターネットに接続していますので、外出先からESP32-CAMの撮影画像を見ることができます。

2、ESP32-CAMのプログラム

ちょっと長いですが、ほどんどはwifiとhttp serverとcameraの設定です。

ESP32をhttp server として立ち上げ、外部からhttpアクセスがあった場合、カメラで画像を撮影し、その画像をクライアントに送信しています。

クライアントに送信は画像ファイルじゃないとできないので、SDカードに画像ファイルを作成したあとでhttpで画像ファイルを送信するようにしています。


#include <esp_camera.h>
#include <FS.h>
#include <SD.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
const char* ssid = your ssid";
const char* password = "your pass";
WebServer server(80);
#define sd_sck 14
#define sd_mosi 15
#define sd_ss 13
#define sd_miso 2

// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
#define CAMERA_MODEL_AI_THINKER
#include "camera_pins.h"
//****************************************************************
void handleNotFound() {
   //  ファイルが見つかりません
   Serial.println("404 not found");
   server.send(404, "text/plain", "File not found in Dongbeino...");
 }
//------------------------------
void handleRoot(){
   cameraShutterOn();
   File file =  SD.open("/test.jpg",FILE_READ);
   server.streamFile(file,"image/jpeg");
   file.close();
   Serial.println("jpeg OK");
   //server.send(200, "text/plain", "Hello ESP32");
}
//-------------------------------
void wifiSetUp(){
 //wifiの設定
 WiFi.mode(WIFI_STA);
 WiFi.begin(ssid, password);
 Serial.println("");
 
 // Wait for connection
 while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   Serial.print(".");
 }
 Serial.println("");
 Serial.print("Connected to ");
 Serial.println(ssid);
 Serial.print("IP address: ");
 Serial.println(WiFi.localIP());
 if (MDNS.begin("esp32cam")) {
   Serial.println("MDNS responder started");
 }

 server.on("/", handleRoot);
 server.onNotFound(handleNotFound);
 server.begin();
 Serial.println("HTTP server started");
 
}
//****************************************************************
void cameraSetUp(){
  static camera_config_t camera_config;
 camera_config.ledc_channel = LEDC_CHANNEL_0;
 camera_config.ledc_timer = LEDC_TIMER_0;
 camera_config.pin_d0 = Y2_GPIO_NUM;
 camera_config.pin_d1 = Y3_GPIO_NUM;
 camera_config.pin_d2 = Y4_GPIO_NUM;
 camera_config.pin_d3 = Y5_GPIO_NUM;
 camera_config.pin_d4 = Y6_GPIO_NUM;
 camera_config.pin_d5 = Y7_GPIO_NUM;
 camera_config.pin_d6 = Y8_GPIO_NUM;
 camera_config.pin_d7 = Y9_GPIO_NUM;
 camera_config.pin_xclk = XCLK_GPIO_NUM;
 camera_config.pin_pclk = PCLK_GPIO_NUM;
 camera_config.pin_vsync = VSYNC_GPIO_NUM;
 camera_config.pin_href = HREF_GPIO_NUM;
 camera_config.pin_sscb_sda = SIOD_GPIO_NUM;
 camera_config.pin_sscb_scl = SIOC_GPIO_NUM;
 camera_config.pin_pwdn = PWDN_GPIO_NUM;
 camera_config.pin_reset = RESET_GPIO_NUM;
 camera_config.xclk_freq_hz = 20000000;
 camera_config.pixel_format = PIXFORMAT_JPEG;
 //init with high specs to pre-allocate larger buffers
 if(psramFound()){
   camera_config.frame_size = FRAMESIZE_UXGA;
   camera_config.jpeg_quality = 10;
   camera_config.fb_count = 2;
 } else {
   camera_config.frame_size = FRAMESIZE_SVGA;
   camera_config.jpeg_quality = 12;
   camera_config.fb_count = 1;
 }
 // camera init
 esp_err_t err = esp_camera_init(&camera_config);
 if (err != ESP_OK) {
   Serial.printf("Camera init failed with error 0x%x", err);
   return;
 }
 sensor_t * s = esp_camera_sensor_get();
 //initial sensors are flipped vertically and colors are a bit saturated
 if (s->id.PID == OV3660_PID) {
   s->set_vflip(s, 1);//flip it back
   s->set_brightness(s, 1);//up the blightness just a bit
   s->set_saturation(s, -2);//lower the saturation
 }
 //drop down frame size for higher initial frame rate
 s->set_framesize(s, FRAMESIZE_QVGA); 
}
//-------------------------------------------------
void cameraShutterOn(){
 /**/
 camera_fb_t * fb = NULL;
 fb = esp_camera_fb_get();
 if (!fb) {
   Serial.println("Camera capture failed");
   return;
 }
 if (fb->len <= 0) {
   Serial.println("capture data size error");
   return;
 }
 SD.begin(sd_ss);
  File file = SD.open("/test.jpg",FILE_WRITE);
  
   if (file.write(fb->buf, fb->len)) {
   Serial.println("File written");
 } else {
   Serial.println("Write failed");
 }
   file.close();
 
 esp_camera_fb_return(fb);
 Serial.println("Finished.");
}
//**************************************************************** 
void setup() {
 Serial.begin(115200);
 Serial.setDebugOutput(true);
 Serial.println();
 SPI.begin(sd_sck,sd_miso,sd_mosi,sd_ss);
 cameraSetUp();
  wifiSetUp();
}
void loop() {
 server.handleClient();
}


3、RaspberryPiのプログラム

ESP32-CAMにhttp getのリクエストでアクセスしESP32-CAMが撮影した画像を取得します。

取得した画像はhttp postでLINE notifyに送ります。

LINE notifyの設定方法は下記を参考にして下さい!


import requests
import pprint
def main():
   send_line_notify('Hello')
def send_line_notify(notification_message):
   url = "http://esp32cam.local"
   res = requests.get(url)
   """
   LINEに通知する
   """
   line_notify_token = 'your notify token'
   line_notify_api = 'https://notify-api.line.me/api/notify'
   headers = {'Authorization': f'Bearer {line_notify_token}'}
   #files = {'imageFile': open("test.jpg", "rb")}
   files = {'imageFile': res.content}
   data = {'message': notification_message}
   response = requests.post(line_notify_api, headers = headers, data = data,files=files)
   pprint.pprint(response.json())
if __name__ == "__main__":
   main()

撮影タイミングはRaspberryPiがコンロトールします。今回はターミナルで実行していますが、センサ、時間、MQTTなど様々なものをトリガーにできると思います。💯

また、RaspberryPiを挟むことによって、ESP32-CAMを複数接続して、複数箇所からの画像を管理することもできますよ。

今回はESP32-CAMの撮影画像をSDカードにファイルにしてから、http送信してますが、なんとかSDカードなしでやりたいですね。

では🤚

この記事が気に入ったらサポートをしてみませんか?