今回は機器の使い方とソフト関係の説明です。。先ずは使い方
- 機器の電源をいれて機器を起動させます。
- 今回はスイッチを容器の中に入れています。
- 下図の左上のネジとESP32CAMの間にある黒い細い棒がそれです。
- スイッチを入れてからふたをするのでちょっと面倒です。
- その他
- 真ん中がカメラのレンズ
- 右側の赤いプッシュスイッチ ー> リセット
- 右側の緑のプッシュスイッチ ー> GIPO0(Boot)
- 機器のReady用LEDが無いので機器の状態が分からないのですが、普通なら10秒位で立ち上がります。
- 次にスマホとWiFiで繋ぎます。
- A: WiFi接続の画面に行き、”ESP32CAM”を選択
- B: パスワード入力の画面で、”12345678”を入力
- C: WiFiには接続出来るのですが、インターネットは利用出来ないと表示されました。
- D: 相手が目の前にあるので非常に強い電波です。
- 次はスマホのブラウザをあげてURL入力欄に、”192.168.4.1”と入力して下さい。
- 最初に下図左側の画面が表示されると思います。このHPで、”Take”ボタンを押すと、撮影した写真が表示されます。
- 簡単な説明
- バッテリー電圧
- バッテリー電圧を表示します。
- 乾電池4本(1.5×4)の電圧ですので、約6V近辺の値。
- 撮影経過時間
- スキップ時間を除いた実際に撮影している時間
- 写真表示部
- 撮影ボタンを押した時の写真をここに表示します。
- 被写体の位置合わせに使います。
- 撮影ボタン
- このボタンを押すと写真が撮れます。
- 撮影間隔時間
- 撮影間隔時間を入力します。左が時、右が分。
- 総撮影時間
- スキップ時間を除いた総撮影時間。
- スキップ
- このカメラで夜の撮影は出来ません。
- そこで撮影しない時間をセットするようにしました。
- ここをチェックしてからスキップ時間の設定を行います。
- 現在の時間
- スキップ時間の計算に使用
- スキップ開始時間
- スキップ終了時間
- スタートロック
- 間違って、”Start”ボタンを押さないように付けました。
- ここをチェックしないと、”Start”ボタンを押せない
- 撮影開始ボタン
- ボタンを押すと撮影が開始されます。
- バッテリー電圧
- その他の注意
- Total時間以外は24時間制で指定して下さい。午前午後の区別は有りません
- 録画をスキップする場合、日にちをまたぐとStart時間よりStop時間が早くなる場合が有ります。
- 例えば、現在が午前10時で、午後8時から次の日の朝3時までスキップする場合、下記の様に入力します。
- Now時間: 10:00
- Start時間: 20:00
- Stop時間: 03:00
- 現在の時間がスキップ時間内でも動作します。例えば、現在10:00。スキップ開始9:00。スキップ終了12:00の場合
- Now: 10:00
- Start: 09:00
- Stop: 12:00
今回のスケッチ
#include "esp_camera.h"
#include "Arduino.h"
#include "SD.h"
#include <WiFi.h>
#include <WebServer.h>
#include "esp_deep_sleep.h"
// Pin definition for 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
#define sd_sck 14
#define sd_mosi 15
#define sd_ss 13
#define sd_miso 2
WebServer server(80);
const char ssid[] = "ESP32CAM"; // SSID
const char pass[] = "12345678"; // password
// Take Picture with Camera
//camera_fb_t * fb = NULL;
RTC_DATA_ATTR int t_time[12]={0};
#define lap_h 0
#define lap_m 1
#define total_h 2
#define total_m 3
#define now_h 4
#define now_m 5
#define start_h 6
#define start_m 7
#define stop_h 8
#define stop_m 9
#define elapse_h 10
#define elapse_m 11
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR int skip_flg = 0;
uint64_t lap_Time = 0;
String index_Dt =
"<!DOCTYPE html>\n<html>\n<head>\n"
"<title>ESP32 Timelapse</title>\n"
"<style type='text/css'>\n"
"button.bt1 {background:#90ee90;font-size:50px;padding:10px;margin:20px;border-radius:30px;box-shadow:4px 4px #555;}\n"
"input.ip1 {font-size:40px;width:100px;}\n"
"input.ip2 {font-size:40px;width:70px;}\n"
"</style>\n</head>\n"
"<body>\n<center>\n"
"<div style='width:700px; background-color:#d8a373; border-style:solid; border-radius:30px; border-color:#6b3f31'>\n"
"<br><span style='font-size:70px'><b><i><u>Timelapse</u></i></b></span><br>\n"
"<span style='font-size:40px' id='p_vol'>50</span><span style='font-size:40px' id='p_no'> Done: xxx</span><br>\n"
"<img src='/data.jpg'>\n"
"<form method='get' style='font-size:40px'>\n"
"<button type='submit' name='1' class='bt1'>Take</button><br></form>\n"
"<form method='get' style='font-size:40px'>\n"
"<span>Lap : <input type='number' max='100' min='0' name='20' class='ip1'/>h\n"
"<input type='number' max='59' min='0' name='21' class='ip2'/>m<br>\n"
"Total:<input type='number' max='10000' min='0' name='22' class='ip1'/>h\n"
"<input type='number' max='59' min='0' name='23' class='ip2'/>m<br><br>\n"
"<input type='checkbox' style='scale:2.5;vertical-align:middle;' onclick='onBtnSkip()' name='30' /> Skip Time<br>\n"
"Now : <input type='number' max='100' min='0' name='24' class='ip1'/>h\n"
"<input type='number' max='59' min='0' name='25' class='ip2'/>m<br>"
"Start : <input type='number' max='100' min='0' name='26' class='ip1'/>h\n"
"<input type='number' max='59' min='0' name='27' class='ip2'/>m<br>\n"
"Stop : <input type='number' max='100' min='0' name='28' class='ip1'/>h\n"
"<input type='number' max='59' min='0' name='29' class='ip2'/>m</span><br>\n"
"<input type='checkbox' style='scale:2.5;vertical-align:middle;' onclick='onBtnStart()' name='31' />\n"
"<button type='submit' class='bt1' id='b_st'>Start</button>\n"
"</form>\n</div>\n</center>\n"
"<script>\n"
"function onBtnStart() {\n"
"if(document.getElementsByName('31')[0].checked)\n document.getElementById('b_st').disabled = '';\n"
"else document.getElementById('b_st').disabled = 'disabled';\n}\n\n"
"function onBtnSkip() {\n"
"if(!document.getElementsByName('30')[0].checked){\n";
void setup() {
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_VGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;
Serial.begin(115200);
// Init Camera
esp_camera_init(&config);
delay(3000);
SPI.begin(sd_sck, sd_miso, sd_mosi, sd_ss);
SD.begin(sd_ss);
esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO);
gpio_pullup_en(GPIO_NUM_0); // use pullup on GPIO
gpio_pulldown_dis(GPIO_NUM_0); // not use pulldown on GPIO
if(esp_sleep_get_wakeup_cause() != 4)
{
Serial.println("Connecting to WiFi");
WiFi.disconnect();
WiFi.softAPdisconnect(true);
delay(500);
WiFi.softAP(ssid, pass);
delay(1000);
Serial.print("AP IP address: ");
Serial.println(WiFi.softAPIP());
server.on("/", handleRoot);
server.onNotFound(handleWebRequests);
server.begin();
Serial.println("HTTP server started");
}
else
{
take_Poto();
switch(check_Next())
{
case 0:
case 1: esp_sleep_enable_timer_wakeup(lap_Time);
break;
case 2: esp_sleep_enable_ext0_wakeup(GPIO_NUM_0,0);
}
esp_deep_sleep_start();
delay(500);
}
}
int check_Next()
{
int a,b,flg;
int d_data[12];
flg=0;
for(a=0; a<12; a++) d_data[a] = t_time[a];
if(check_Two(&d_data[total_h], &d_data[elapse_h])) flg=2;
// esp_sleep_enable_ext0_wakeup(GPIO_NUM_16,0);
else
{
if(skip_flg) // Skip = On
{
if(check_Two(&d_data[start_h], &d_data[stop_h])) // start < stop
{
if(check_Two(&d_data[stop_h], &d_data[now_h])) ; // now >= stop
else // now < stop
{
if(check_Two(&d_data[start_h], &d_data[now_h])) // start =< now
{
calc_Wait(0); flg=1;
}
}
}
else // start > stop
{
if(check_Two(&d_data[start_h], &d_data[now_h])) // now > start
{
calc_Wait(1); flg=1;
}
}
}
}
if(flg == 0)
{
lap_Time = t_time[lap_h] * 60 + t_time[lap_m];
t_time[now_m] += t_time[lap_m];
if(t_time[now_m] > 59)
{
t_time[now_m] -= 60;
t_time[now_h] ++;
}
t_time[now_h] += t_time[lap_h];
if(t_time[now_h] > 23) t_time[now_h] -= 24;
t_time[elapse_m] += t_time[lap_m];
if(t_time[elapse_m] > 59)
{
t_time[elapse_m] -= 60;
t_time[elapse_h] ++;
}
t_time[elapse_h] += t_time[lap_h];
}
//Set timer
lap_Time *= 60000000;
return(flg);
}
int check_Two(int *st, int *sp)
{
// st - sp then, st > sp :0 st =< sp :1
int a,b,c;
a = st[0];
b = st[1] - sp[1];
if(b < 0) a --;
a -= sp[0];
c=0;
if(a < 0) c=1;
else
if(a == 0 && b < 1) c=1;
return (c);
}
void calc_Wait(int flg)
{
int a,b;
b = t_time[stop_h];
if(flg) b += 24;
a = t_time[stop_m] - t_time[now_m];
if( a < 0)
{
a = t_time[stop_m] + 60 - t_time[now_m];
b --;
}
b -= t_time[now_h];
lap_Time = b * 60 + a;
t_time[now_h] = t_time[stop_h];
t_time[now_m] = t_time[stop_m];
}
void loop() {
server.handleClient();
}
void handleRoot() {
String cmd,buf;
int a,b,flg;
File dataFile;
camera_fb_t * fb = NULL;
float d_vol;
char temp[16];
flg=0;
cmd=server.argName(0);
switch(cmd.toInt())
{
case 1: // Start Log
fb = esp_camera_fb_get();
dataFile = SD.open("/data.jpg", FILE_WRITE);
dataFile.write(fb->buf, fb->len); // payload (image), payload length
dataFile.close();
esp_camera_fb_return(fb);
Serial.printf("Take a photo.\n");
break;
case 20: // Start Log
skip_flg=1; b=30;
if(server.arg("30") == "") { skip_flg=0; b=24; }
for(a=20; a<b; a++)
{
cmd=server.arg(String(a));
t_time[a-20]=cmd.toInt();
}
t_time[elapse_h] = t_time[elapse_m] = 0;
bootCount = 0;
switch(check_Next())
{
case 0: take_Poto();
case 1: esp_sleep_enable_timer_wakeup(lap_Time);
break;
case 2: esp_sleep_enable_ext0_wakeup(GPIO_NUM_0,0);
break;
}
flg=1;
for(a=0; a<12; a += 2)
Serial.println(String(a) + "=" + String(t_time[a]) + ":" + String(t_time[a+1]));
break;
}
buf=index_Dt;
for(a=24; a<29; a++)
buf += ("document.getElementsByName('" + String(a) + "')[0].disabled =\n");
buf += "document.getElementsByName('29')[0].disabled =true;}\nelse{\n";
for(a=24; a<29; a++)
buf += ("document.getElementsByName('" + String(a) + "')[0].disabled =\n");
buf += "document.getElementsByName('29')[0].disabled =false;}}\n\n";
d_vol = analogRead(33);
d_vol *= 3.3; d_vol /= 2048;
dtostrf(d_vol, 5, 2,temp);
cmd=temp;
buf += ("document.getElementById('p_vol').innerHTML=\"Battery: " + cmd + " V \";\n");
buf += ("document.getElementById('p_no').innerHTML=\"Elapsed: " + String(t_time[elapse_h]) + ":" + String(t_time[elapse_m]) + "\";\n\n");
for(a=20; a<30; a++)
buf += ("document.getElementsByName('" + String(a) + "')[0].value=" + String(t_time[a-20]) +";\n");
if(skip_flg)
buf += "document.getElementById('lap').checked=true;\n";
buf += "onBtnStart();\nonBtnSkip();\nhistory.pushState(null,null,'/');\n</script>\n</body>\n</html>";
server.send(200, "text/html", buf);
if(flg)
{
esp_deep_sleep_start();
delay(500);
}
}
void handleWebRequests()
{
String dataType = "text/plain";
String path;
File dataFile;
path = server.uri();
if(path.endsWith(".txt")) dataType = "text/plain";
else if(path.endsWith(".css")) dataType = "text/css";
else if(path.endsWith(".js")) dataType = "application/javascript";
else if(path.endsWith(".png")) dataType = "image/png";
else if(path.endsWith(".gif")) dataType = "image/gif";
else if(path.endsWith(".jpg")) dataType = "image/jpeg";
delay(5);
dataFile = SD.open(path.c_str(), "r");
server.streamFile(dataFile, dataType);
dataFile.close();
delay(5);
}
void take_Poto()
{
File dataFile;
camera_fb_t * fb = NULL;
String f_name;
char s_name[15];
fb = esp_camera_fb_get();
sprintf(s_name,"%08d",bootCount);
f_name = s_name;
f_name = "/" + f_name + ".jpg" ;
dataFile = SD.open(f_name, FILE_WRITE);
dataFile.write(fb->buf, fb->len); // payload (image), payload length
dataFile.close();
esp_camera_fb_return(fb);
bootCount ++;
Serial.println("No." + String(bootCount));
}
先ずはこれで撮影して見ます。