tAROの試行錯誤

技術的なことを色々試した過程を記録

Timer Camera Xで定点観測カメラを作る(その2)

前回からの続きです。

isogabamaware.hatenadiary.jp

前回は以下の1、2を作ったので、今回は3を作ります。

  1. Node-REDでhttpで画像を送受信し、表示する環境を作る
  2. TimerCameraXで撮影した画像をPC上で確認する
  3. TimerCameraXからhttpでNode-REDに画像を送信する
  4. TimerCameraXをディープスリープさせて定期的に撮影するようにする
  5. AWS部分を作り、node-redから画像を送信する
  6. TimerCameraXとAWSをつなぐ

3. TimerCameraXからhttpでNode-REDに画像を送信する

撮影してbase64にしてシリアルモニタに表示するところまでは前回作ったので、今回はbase64のデータをhttp POSTします。 http post arduinoで検索します。

2番目に出てきたここが良さそうです。ちょうどNode-REDとやりとりするサンプルがあります。

randomnerdtutorials.com

http POSTの方法として以下の3通りがあるようです。

  1. URLに埋め込む
  2. JSONオブジェクトを送る
  3. プレーンテキストを送る

まずは一番簡単そうな3のプレーンテキストを試してみます。 これだけで送れそうですね。

#include <HTTPClient.h>

http.begin(serverName);
http.addHeader("Content-Type", "text/plain");
int httpResponseCode = http.POST("Hello, World!");

これの"Hello, World!"の部分をbase64の文字列に置き換えれば行けちゃいそうなので試してみます。 serverNameにはNode-REDの画像受信のURLを入れます。

char *serverName = "http://192.168.0.16:1880/image";

ということで以下がコード全体です。前回printのために終端文字を入れていたのがここでもそのまま使えました。 printしていたbase64buffをそのままhttp.POSTしたらできちゃいました。

#include "esp_camera.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <base64.hpp>
#include "camera_pins.h"

const char* ssid = "";
const char* password = "";

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();

  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.frame_size = FRAMESIZE_UXGA;
  config.jpeg_quality = 10;
  config.fb_count = 2;
 
  // 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;
  }

  sensor_t * s = esp_camera_sensor_get();
  //initial sensors are flipped vertically and colors are a bit saturated
  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);

  if (ssid=="")
    WiFi.begin();
  else
    WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
}

void loop() {
  camera_fb_t *fb = esp_camera_fb_get();
  if ( fb ) {
    Serial.printf("width: %d, height: %d, buf: 0x%x, len: %d\n", fb->width, fb->height, fb->buf, fb->len);
    unsigned int base64_length = encode_base64_length(fb->len);
    unsigned char *base64buff = new unsigned char[base64_length+1];
    base64buff[base64_length] = '\0';
    encode_base64(fb->buf, fb->len, base64buff);
    char *serverName = "http://192.168.0.16:1880/image";
    HTTPClient http;
    http.begin(serverName);
    http.addHeader("Content-Type", "text/plain");
    int httpResponseCode = http.POST(reinterpret_cast<char*>(base64buff));
    Serial.printf("%d", httpResponseCode);
    delete [] base64buff;
    esp_camera_fb_return(fb);
  }
  delay(100);
}

せっかくなのでカメラから送信してNode-REDのダッシュボードに表示した画面を貼ってみます。 Macではshift+command+5で範囲を指定したスクリーンキャプチャ動画が取れるみたいです。

support.apple.com

範囲を指定して、キャプチャボタンを押したのですが、止め方がわからない・・・と思ったら、タッチバーに停止ボタンがありました。 撮影完了したらgif動画に変換します。 今後のことも考えてffmpegを入れておきます。 ちょうど以下のサイトにffmpegをインストールしてmovをgifに変換するサンプルがあったので、その通り実行してgif動画を作成します。

codelab.website

というわけで、今回の成果物です。 思ったより簡単にTimerCameraXから定期的に画像を送信することができました。

f:id:tARO:20210125221631g:plain

無事やりたいことに近づいています。 次回はTimerCameraの名前の通り、定期的にディープスリープして撮影する部分を試してみます。 電源周りは全くわかっていないので、できるかどうか、、、