diff --git a/esp32cam-demo.ino b/esp32cam-demo.ino index f7fcee7..240c976 100644 --- a/esp32cam-demo.ino +++ b/esp32cam-demo.ino @@ -101,7 +101,7 @@ // --------------------------------------------------------------- const char* stitle = "ESP32Cam-demo"; // title of this sketch - const char* sversion = "02Jan22"; // Sketch version + const char* sversion = "03Jan22"; // Sketch version bool sendRGBfile = 0; // if set '/rgb' will send the rgb data as a file rather than display some on a HTML page @@ -192,7 +192,6 @@ WebServer server(80); // serve web pages on port 80 // Define some global variables: uint32_t lastStatus = millis(); // last time status light changed status (to flash all ok led) - uint32_t lastCamera = millis(); // timer for periodic image capture bool sdcardPresent; // flag if an sd card is detected int imageCounter; // image file name on sd card counter uint32_t illuminationLEDstatus; // current brightness setting of the illumination led @@ -233,7 +232,7 @@ void setup() { Serial.print(SSID_NAME); Serial.print("\n "); } - WiFi.begin(SSID_NAME, SSID_PASWORD); // can be set in platformio.ini + WiFi.begin(SSID_NAME, SSID_PASWORD); while (WiFi.status() != WL_CONNECTED) { delay(500); if (serialDebug) Serial.print("."); @@ -336,7 +335,7 @@ void setup() { digitalWrite(indicatorLED,HIGH); // led off = High pinMode(iopinA, OUTPUT); // pin 13 - free io pin, can be used for input or output pinMode(iopinB, OUTPUT); // pin 12 - free io pin, can be used for input or output (must not be high at boot) - pinMode(iopinC, INPUT); // pin 16 - free input only pin + pinMode(iopinC, INPUT); // pin 16 - free input only pin (may cause issues?) // MCP23017 io expander (requires adafruit MCP23017 library) #if useMCP23017 == 1 @@ -349,13 +348,13 @@ void setup() { // read pin state with mcp.digitalRead(8) #endif - // set up bright LED (flash) + // set up illumination LED (flash) ledcSetup(ledChannel, ledFreq, ledRresolution); ledcAttachPin(brightLED, ledChannel); brightLed(0); // change bright LED // startup complete - if (serialDebug) Serial.println("\nSetup complete..."); + if (serialDebug) Serial.println("\nStarted..."); brightLed(64); // change bright LED delay(200); brightLed(0); // change bright LED @@ -363,10 +362,11 @@ void setup() { } // setup -// change bright LED illumination level +// change illumination LED brightness void brightLed(byte ledBrightness){ brightLEDbrightness = ledBrightness; // store setting ledcWrite(ledChannel, ledBrightness); // change LED brightness (0 - 255) + if (serialDebug) Serial.println("Brightness changed to " + String(ledBrightness) ); } @@ -394,10 +394,12 @@ void loop() { -// // demo to Capture an image and save to sd card every 5 seconds (i.e. time lapse) +// // Capture an image and save to sd card every 5 seconds (i.e. time lapse) +// static uint32_t lastCamera = millis(); // if ( ((unsigned long)(millis() - lastCamera) >= 5000) && sdcardPresent ) { // lastCamera = millis(); // reset timer // storeImage(); // save an image to sd card +// if (serialDebug) Serial.println("Time lapse image captured"); // } // flash status LED to show sketch is running ok @@ -421,7 +423,6 @@ void loop() { bool initialiseCamera() { camera_config_t config; - config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; @@ -484,6 +485,8 @@ bool initialiseCamera() { bool cameraImageSettings() { + if (serialDebug) Serial.println("Applying camera settings"); + sensor_t *s = esp_camera_sensor_get(); // something to try?: if (s->id.PID == OV3660_PID) if (s == NULL) { @@ -571,10 +574,11 @@ void flashLED(int reps) { // critical error - stop sketch and continually flash error code on indicator led void showError(int errorNo) { - while(1) { + if (serialDebug) Serial.println("Critical Error: " + String(errorNo) ); + while(1) { // repeat forever flashLED(errorNo); delay(4000); - } + } } @@ -593,7 +597,7 @@ byte storeImage() { // capture the image from camera int currentBrightness = brightLEDbrightness; if (flashRequired) brightLed(255); // change LED brightness (0 - 255) - camera_fb_t *fb = esp_camera_fb_get(); // capture image frame from camera + camera_fb_t *fb = esp_camera_fb_get(); // capture image frame from camera if (flashRequired) brightLed(currentBrightness); // change LED brightness back to previous state if (!fb) { if (serialDebug) Serial.println("Error: Camera capture failed"); @@ -691,27 +695,38 @@ void handleRoot() { // if button1 was pressed (toggle io pin A) // Note: if using an input box etc. you would read the value with the command: String Bvalue = server.arg("demobutton1"); if (server.hasArg("button1")) { - digitalWrite(iopinA,!digitalRead(iopinA)); // toggle output pin on/off if (serialDebug) Serial.println("Button 1 pressed"); + digitalWrite(iopinA,!digitalRead(iopinA)); // toggle output pin on/off } // if button2 was pressed (toggle io pin B) if (server.hasArg("button2")) { - digitalWrite(iopinB,!digitalRead(iopinB)); // toggle output pin on/off if (serialDebug) Serial.println("Button 2 pressed"); + digitalWrite(iopinB,!digitalRead(iopinB)); // toggle output pin on/off } // if button3 was pressed (toggle flash LED) if (server.hasArg("button3")) { + if (serialDebug) Serial.println("Button 3 pressed"); if (brightLEDbrightness == 0) brightLed(10); // turn led on dim else if (brightLEDbrightness == 10) brightLed(40); // turn led on medium else if (brightLEDbrightness == 40) brightLed(255); // turn led on full else brightLed(0); // turn led off - if (serialDebug) Serial.println("Button 3 pressed"); } + // if button4 was pressed (format SPIFFS) + if (server.hasArg("button4")) { + if (serialDebug) Serial.println("Button 4 pressed"); + if (!SPIFFS.format()) { + if (serialDebug) Serial.println("Error: Unable to format Spiffs"); + } else { + if (serialDebug) Serial.println("Spiffs memory has been formatted"); + } + } + // if exposure was adjusted - cameraImageExposure if (server.hasArg("exp")) { + if (serialDebug) Serial.println("Exposure has been changed"); String Tvalue = server.arg("exp"); // read value if (Tvalue != NULL) { int val = Tvalue.toInt(); @@ -725,6 +740,7 @@ void handleRoot() { // if image gain was adjusted - cameraImageGain if (server.hasArg("gain")) { + if (serialDebug) Serial.println("Gain has been changed"); String Tvalue = server.arg("gain"); // read value if (Tvalue != NULL) { int val = Tvalue.toInt(); @@ -781,7 +797,8 @@ void handleRoot() { // Control bottons client.write(" \n"); client.write(" \n"); - client.write("
\n"); + client.write(" \n"); + client.write("
\n"); // Image setting controls client.write("
CAMERA SETTINGS: \n"); @@ -792,7 +809,7 @@ void handleRoot() { // links to the other pages available client.write("
LINKS: \n"); client.write("Capture an image - \n"); - client.write("View stored images - \n"); + client.write("View stored image - \n"); client.write("Capture Image as raw RGB data - \n"); client.write("Live stream
\n"); @@ -937,8 +954,7 @@ void handleNotFound() { String tReply; - // log page request - if (serialDebug) Serial.print("Invalid page requested"); + if (serialDebug) Serial.print("Invalid page requested"); tReply = "File Not Found\n\n"; tReply += "URI: "; @@ -965,9 +981,10 @@ void handleNotFound() { // send line of text to both serial port and web page void MessageRGB(WiFiClient &client, String theText) { if (!sendRGBfile) client.print(theText + "
\n"); - if (serialDebug || theText.indexOf("error") > 0) Serial.println(theText); + if (serialDebug || theText.indexOf("error") > 0) Serial.println(theText); // if text contains "error" } + // ---------------------------------------------------------------- // -access image data as RGB - i.e. http://x.x.x.x/rgb // ---------------------------------------------------------------- @@ -1003,6 +1020,7 @@ void readRGBImage() { camera_fb_t * fb = NULL; tTimer = millis(); // store time that image capture started fb = esp_camera_fb_get(); + if (!fb) MessageRGB(client,"error: failed to capture image"); MessageRGB(client, "-Image capture took " + String(millis() - tTimer) + " milliseconds"); // report time it took to capture an image if (!fb) MessageRGB(client," -error capturing image from camera- "); else { @@ -1085,21 +1103,28 @@ void readRGBImage() { bool getNTPtime(int sec) { - { - uint32_t start = millis(); + uint32_t start = millis(); // timeout timer + do { time(&now); localtime_r(&now, &timeinfo); - Serial.print("."); + if (serialDebug) Serial.print("."); delay(100); } while (((millis() - start) <= (1000 * sec)) && (timeinfo.tm_year < (2016 - 1900))); + if (timeinfo.tm_year <= (2016 - 1900)) return false; // the NTP call was not successful - Serial.print("now "); Serial.println(now); - char time_output[30]; - strftime(time_output, 30, "%a %d-%m-%y %T", localtime(&now)); - Serial.println(time_output); - Serial.println(); - } + if (serialDebug) { + Serial.print("now "); + Serial.println(now); + } + + // Display time + if (serialDebug) { + char time_output[30]; + strftime(time_output, 30, "%a %d-%m-%y %T", localtime(&now)); + Serial.println(time_output); + Serial.println(); + } return true; } @@ -1109,47 +1134,51 @@ bool getNTPtime(int sec) { // ---------------------------------------------------------------- // Capture image and send as a jpg -void handleJPG(){ +void handleJPG() { - WiFiClient client = server.client(); // open link with client + WiFiClient client = server.client(); // open link with client - // log page request including clients IP address - if (serialDebug) { - IPAddress cip = client.remoteIP(); - Serial.printf("jpg requested from: %d.%d.%d.%d \n", cip[0], cip[1], cip[2], cip[3]); - } + // log page request including clients IP address + if (serialDebug) { + IPAddress cip = client.remoteIP(); + Serial.printf("jpg requested from: %d.%d.%d.%d \n", cip[0], cip[1], cip[2], cip[3]); + } - // HTML used in the web page - const char HEADER[] = "HTTP/1.1 200 OK\r\n" \ - "Access-Control-Allow-Origin: *\r\n" \ - "Content-Type: multipart/x-mixed-replace; boundary=123456789000000000000987654321\r\n"; - const char BOUNDARY[] = "\r\n--123456789000000000000987654321\r\n"; // marks end of each image frame - const char CTNTTYPE[] = "Content-Type: image/jpeg\r\nContent-Length: "; // marks start of image data - const int hdrLen = strlen(HEADER); // length of the stored text, used when sending to web page - const int bdrLen = strlen(BOUNDARY); - const int cntLen = strlen(CTNTTYPE); + // HTML used in the web page + const char HEADER[] = "HTTP/1.1 200 OK\r\n" \ + "Access-Control-Allow-Origin: *\r\n" \ + "Content-Type: multipart/x-mixed-replace; boundary=123456789000000000000987654321\r\n"; + const char BOUNDARY[] = "\r\n--123456789000000000000987654321\r\n"; // marks end of each image frame + const char CTNTTYPE[] = "Content-Type: image/jpeg\r\nContent-Length: "; // marks start of image data + const int hdrLen = strlen(HEADER); // length of the stored text, used when sending to web page + const int bdrLen = strlen(BOUNDARY); + const int cntLen = strlen(CTNTTYPE); - // temp stores - char buf[32]; - int s; - camera_fb_t * fb = NULL; + // temp stores + char buf[32]; + int s; + camera_fb_t * fb = NULL; - // send html header - client.write(HEADER, hdrLen); - client.write(BOUNDARY, bdrLen); + // send html header + client.write(HEADER, hdrLen); + client.write(BOUNDARY, bdrLen); - // send live image - fb = esp_camera_fb_get(); // capture live image - s = fb->len; // store size of image (i.e. buffer length) - client.write(CTNTTYPE, cntLen); // send content type html (i.e. jpg image) - sprintf( buf, "%d\r\n\r\n", s ); // format the image's size as html and put in to 'buf' - client.write(buf, strlen(buf)); // send result (image size) - client.write((char *)fb->buf, s); // send the image data - client.write(BOUNDARY, bdrLen); // send html boundary see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type - esp_camera_fb_return(fb); // return image so memory can be released + // capture and send image + fb = esp_camera_fb_get(); // capture live image + if (!fb) { + if (serialDebug) Serial.println("Error: failed to capture image"); + return; // capture failed + } + s = fb->len; // store size of image (i.e. buffer length) + client.write(CTNTTYPE, cntLen); // send content type html (i.e. jpg image) + sprintf( buf, "%d\r\n\r\n", s ); // format the image's size as html and put in to 'buf' + client.write(buf, strlen(buf)); // send result (image size) + client.write((char *)fb->buf, s); // send the image data + client.write(BOUNDARY, bdrLen); // send html boundary see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + esp_camera_fb_return(fb); // return image so memory can be released - delay(3); - client.stop(); + delay(3); + client.stop(); } // handleJPG @@ -1193,6 +1222,9 @@ void handleStream(){ { if (!client.connected()) break; fb = esp_camera_fb_get(); // capture live image + if (!fb) { + if (serialDebug) Serial.println("Error: failed to capture image"); + } s = fb->len; // store size of image (i.e. buffer length) client.write(CTNTTYPE, cntLen); // send content type html (i.e. jpg image) sprintf( buf, "%d\r\n\r\n", s ); // format the image's size as html and put in to 'buf'