I thought I had a problem, now I'm not sure, well obviously I have problems, but I'm so tired that I've broken off the lens and the CCD is bare, the pictures are so random and even look like they are moving, yup, problems... I thought / think that when clicking to take a new photo that it stores something from a buffer (???) which is two images previous... So I rewrote the code back to bare essentials and into a single file, but now I'm not so sure that it's saving old images, anyway...
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
//#include <ESPAsyncWebServer.h>
#include <ESPAsyncWebSrv.h>
#include "esp_camera.h"
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
//#include "driver/rtc_io.h"
#include <EEPROM.h> // read and write from flash memory
#include "FS.h"
#include "SD_MMC.h" // SD Card ESP32
const char* ssid = "ssid"; //Write your own Wi-Fi name here
const char* password = "password"; //Write your own password here
IPAddress local_IP(192, 168, 1, 200);
IPAddress gateway(192, 168, 1, 255);
IPAddress subnet(255, 255, 0, 0);
IPAddress primaryDNS(8, 8, 8, 8);
IPAddress secondaryDNS(8, 8, 4, 4);
AsyncWebServer server(80); //object created on default port 80
// define the number of bytes you want to access
#define EEPROM_SIZE 1
// 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
char webpage[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<title>CCam</title>
<style>
body(background-color:rgba(128,128,128, 0.8)}
</style>
</head>
<body>
<div>
<div style="width:90%">
<h2>CCam</h2>
<button onclick="photo()">Photo</button><br /><br />
</div>
<div>
<div id="" style="float:left;padding:15px;">
<b>Files</b><br />
<div>
<button onclick="fm_refresh()">Refresh</button>
</div>
<div id="div_dir" style="width:250px;height:300px;overflow:scroll;"></div>
</div>
<div id="" style="float:left;padding:15px;width:50%;">
<img src='' id='img1' name='img1' style="width:50%;">
</div>
</div>
</div>
<script>
function photo()
{
var req = new XMLHttpRequest();
req.onreadystatechange = function()
{
if(this.readyState == 4 && this.status == 200)
{
//document.getElementById("div_dir2").innerHTML = this.responseText;
}
};
req.open("GET", "photo", true);
req.send();
}
function img_set(fn) {
var pic = document.getElementById("img1");
//pic.src = "img?fn=picture4.jpg";
pic.src = "img?fn=" + fn;
}
function fm_refresh()
{
var req = new XMLHttpRequest();
req.onreadystatechange = function()
{
if(this.readyState == 4 && this.status == 200)
{
var data = JSON.parse(this.responseText);
var ss = "<ul>";
var len = data.length;
for(var i=0;i<len;i++ ){
ss += "<li onclick=\"img_set('" + data[i][1] + "')\">" + data[i][1] + "</li>";
}
ss += "</ul>";
document.getElementById("div_dir").innerHTML = ss;
}
};
req.open("GET", "ls", true);
req.send();
}
</script>
</body>
</html>)=====";
void init_wifi()
{
// Configures static IP address
if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS))
{
Serial.println("Static IP Fail");
}
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("Connecting WiFi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void init_sd()
{
//if(!SD_MMC.begin())
if(!SD_MMC.begin("/sdcard", true)) // disables the flash!!! yeah!
{
Serial.println("Initialization Failed");
return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("SD card is not present!");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
uint64_t card_free = SD_MMC.usedBytes(); // / (1024 * 1024);
//Serial.printf("SD Card Used: %lluMB\n", card_free);
Serial.printf("SD Card Used: %lluB\n", card_free);
}
int fs_file_exist(fs::FS &fs, const char * path){
File file = fs.open(path);
if(!file){
return 0; // file not exist
}
return 1; // file exists
}
String dir_list(fs::FS &fs, const char * dirname)
{
String s = "";
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return s;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return s;
}
s += "[";
File file = root.openNextFile();
while(file){
if(!file.isDirectory())
{
String fn = file.name();
if(fn.endsWith(".jpg"))
{
s += "[\"f\",\"" + fn + "\"],";
}
}
file = root.openNextFile();
}
s = s.substring(0, s.length()-1);
s += "]";
return s;
}
void cam_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;
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// initialize EEPROM with predefined size
EEPROM.begin(EEPROM_SIZE);
//pictureNumber = EEPROM.read(0) + 1;
//cam_pic();
}
void cam_pic()
{
camera_fb_t * fb = NULL;
// Take Picture with Camera
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
}
int pictureNumber = EEPROM.read(0) + 1;
// Path where new picture will be saved in SD Card
String path = "/picture" + String(pictureNumber) +".jpg";
fs::FS &fs = SD_MMC;
Serial.printf("Picture file name: %s\n", path.c_str());
File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println("Failed to open file in writing mode");
}
else {
file.write(fb->buf, fb->len); // payload (image), payload length
Serial.printf("Saved file to path: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
}
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
Serial.begin(115200);
init_sd();
init_wifi();
cam_setup();
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{
// http://192.168.1.200/
request->send(200, "text/html", webpage);
});
server.on("/img", HTTP_GET, [](AsyncWebServerRequest *request)
{
// http://192.168.1.200/img?fn=picture4.jpg
bool flag = true;
if(request->hasParam("fn", false)) // for GET
{
String fn = request->getParam("fn", false)->value(); // for GET
fn = "/" + fn;
if(fs_file_exist(SD_MMC, fn.c_str())){
flag = false;
// RETURN REQUESTED IMAGE
request->send(SD_MMC, fn.c_str(), "image/jpeg");
}
}
if(flag)
{
// RETURN DEFAULT IMAGE (e.g. latest, first)
request->send(SD_MMC, "/picture3.jpg", "image/jpeg");
}
});
server.on("/ls", HTTP_GET, [](AsyncWebServerRequest *request)
{
// http://192.168.1.200/ls
//String msg = "[[\"f\", \"picture4.jpg\"],[\"f\",\"picture3.jpg\"]]";
String msg = dir_list(SD_MMC, "/");
Serial.println(msg);
request->send(200, "application/json", msg);
});
server.on("/photo", HTTP_GET, [](AsyncWebServerRequest *request)
{
// http://192.168.1.200/photo
cam_pic();
request->send(200, "text/html", "ok");
});
server.begin();
}
void loop() {
// put your main code here, to run repeatedly:
}