--> -->
前回の記事で味を占め、ESP32-CAMを使って定期的に写真を撮ってサーバーに転送してみました。
例によってAliExpressで送料込みで900円ほどです。
https://ja.aliexpress.com/item/1005001970568846.html
#ref(): File not found: "cam.png" at page "skimemo - 日記/2021-06-27/ESP32-CAMで写真を撮ってサーバーに転送する"
このESP32-CAM(単体)は以下の点が要注意です。
上記の商品はMBという開発用ボードがセットになっており、ここにUSB接続することでプログラムを書き込めます。
#include "esp_camera.h"
#include
#include
#include
#include
#define WIFI_SSID "[SSID]"
#define WIFI_PASSWORD "[PASSWORD]"
#define UPLOAD_INTERVAL 15000 // WEB upload interval(ms)
#define STRING_BOUNDARY "ABCDEFG0123456789"
#define STRING_MULTIHEAD1 "Content-Disposition: form-data; name=\"uploadFile\"; filename=\"./camera.jpg\""
#define STRING_MULTIHEAD2 "Content-Type: image/jpeg"
#define STATUS_SUCCESS 0;
#define STATUS_CAMERA_FAILED 1;
#define STATUS_SAVE_FAILED 2;
WiFiMulti wifiMulti;
//TEST
const int ledPin = 4;
constexpr int kCameraPin_PWDN = 32;
constexpr int kCameraPin_RESET = -1; // NC
constexpr int kCameraPin_XCLK = 0;
constexpr int kCameraPin_SIOD = 26;
constexpr int kCameraPin_SIOC = 27;
constexpr int kCameraPin_Y9 = 35;
constexpr int kCameraPin_Y8 = 34;
constexpr int kCameraPin_Y7 = 39;
constexpr int kCameraPin_Y6 = 36;
constexpr int kCameraPin_Y5 = 21;
constexpr int kCameraPin_Y4 = 19;
constexpr int kCameraPin_Y3 = 18;
constexpr int kCameraPin_Y2 = 5;
constexpr int kCameraPin_VSYNC = 25;
constexpr int kCameraPin_HREF = 23;
constexpr int kCameraPin_PCLK = 22;
void setupCamera() {
const camera_config_t config = {
.pin_pwdn = kCameraPin_PWDN,
.pin_reset = kCameraPin_RESET,
.pin_xclk = kCameraPin_XCLK,
.pin_sscb_sda = kCameraPin_SIOD,
.pin_sscb_scl = kCameraPin_SIOC,
.pin_d7 = kCameraPin_Y9,
.pin_d6 = kCameraPin_Y8,
.pin_d5 = kCameraPin_Y7,
.pin_d4 = kCameraPin_Y6,
.pin_d3 = kCameraPin_Y5,
.pin_d2 = kCameraPin_Y4,
.pin_d1 = kCameraPin_Y3,
.pin_d0 = kCameraPin_Y2,
.pin_vsync = kCameraPin_VSYNC,
.pin_href = kCameraPin_HREF,
.pin_pclk = kCameraPin_PCLK,
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,
// .frame_size = FRAMESIZE_96X96,
// .frame_size = FRAMESIZE_QQVGA,
// .frame_size = FRAMESIZE_QCIF,
// .frame_size = FRAMESIZE_QCIF,
// .frame_size = FRAMESIZE_HQVGA,
// .frame_size = FRAMESIZE_240X240,
// .frame_size = FRAMESIZE_QVGA,
// .frame_size = FRAMESIZE_CIF,
// .frame_size = FRAMESIZE_HVGA,
.frame_size = FRAMESIZE_VGA,
// .frame_size = FRAMESIZE_SVGA,
// .frame_size = FRAMESIZE_XGA,
// .frame_size = FRAMESIZE_HD,
// .frame_size = FRAMESIZE_SXGA,
// .frame_size = FRAMESIZE_UXGA,
.jpeg_quality = 12,
.fb_count = 1,
};
if(kCameraPin_PWDN != -1){
pinMode(kCameraPin_PWDN, OUTPUT);
digitalWrite(kCameraPin_PWDN, LOW);
}
esp_err_t err = esp_camera_init(&config);
Serial.printf("esp_camera_init: 0x%x\n", err);
// init flash pin
pinMode(ledPin, OUTPUT);
}
void flash(bool flag) {
if(flag) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
int post(camera_fb_t *fb, uint8_t msg) {
String str = "";
// Wifi
if ((wifiMulti.run() == WL_CONNECTED)) {
String post = "status=" + String(msg);
HTTPClient http;
uint8_t httpCode;
// POST
http.begin("http://[SERVER_NAME]/post.php");
if(!fb) {
char buf[512];
String post = "status=false";
post.toCharArray(buf, post.length());
http.addHeader("Content-Type", "application/x-www-form-urlencoded", false, true);
httpCode = http.POST((uint8_t*)buf, strlen(buf));
} else {
str = "multipart/form-data; boundary=";
str += STRING_BOUNDARY;
http.addHeader("Content-Type", str);
// 構造定義
String head1 = "--";
head1 +=STRING_BOUNDARY;
head1 += "\r\n";
head1 += STRING_MULTIHEAD1;
head1 += "\r\n";
head1 += STRING_MULTIHEAD2;
head1 += "\r\n\r\n";
uint32_t clen1 = head1.length();
String head2 = "\r\n--";
head2 += STRING_BOUNDARY;
head2 += "--\r\n\r\n";
uint32_t clen2 = head2.length();
uint32_t clen = clen1 + clen2 + fb->len;
uint8_t *uiB = (uint8_t *)malloc(sizeof(uint8_t)*clen);
Serial.printf("length: head1=%d, head2=%d, fb=%d, total=%d",clen1,clen2,fb->len,clen);
// POST
for(int pos=0;poslen);pos++){
uiB[clen1+pos]=(fb->buf)[pos];
}
for(int pos=0;poslen)+pos]=head2[pos];
}
httpCode = http.POST(uiB,clen);
free(uiB);
}
// 結果確認
if(httpCode > 0) {
Serial.printf("[HTTP] POST... code: %d\n", httpCode);
// HTTP OK
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("WIFI NOT CONNECTED.\n");
}
}
void setup() {
Serial.begin(115200, SERIAL_8N1);
// init camera
setupCamera();
// Wifi
wifiMulti.addAP(WIFI_SSID, WIFI_PASSWORD);
}
void loop() {
uint16_t msg = 0;
Serial.println("-----------------");
// take a picture
Serial.println("Taking a photo...");
flash(true);
camera_fb_t *fb = esp_camera_fb_get();
flash(false);
if (!fb) {
Serial.println("Camera capture failed");
msg = STATUS_CAMERA_FAILED;
post(fb, msg);
} else {
msg = STATUS_SUCCESS;
// post to wifi
Serial.printf("Picture taken.Its size was: %zu bytes.\n",fb->len);
post(fb, msg);
esp_camera_fb_return(fb);
}
delay(UPLOAD_INTERVAL);
}
Tweet