2020-09-26 14:35:33 +00:00
/*******************************************************************************************************************
2021-11-21 21:21:37 +00:00
*
* ESP32Cam development board demo sketch using Arduino IDE or PlatformIO
2020-09-26 14:35:33 +00:00
* Github : https : //github.com/alanesq/ESP32Cam-demo
2021-11-21 21:21:37 +00:00
*
* Tested with ESP32 board manager version 1.0 .6
*
2020-09-26 14:35:33 +00:00
* Starting point sketch for projects using the esp32cam development board with the following features
2020-11-14 16:20:58 +00:00
* web server with live video streaming and RGB data from camera demonstrated .
* sd card support using 1 - bit mode ( data pins are usually 2 , 4 , 12 & 13 but using 1 bit mode only uses pin 2 )
* flash led is still available for use ( pin 4 ) and does not flash when accessing sd card
2020-12-10 11:08:04 +00:00
* Stores image in Spiffs if no sd card present
* PWM control of the illumination / flash LED
2021-11-21 21:21:37 +00:00
*
2020-11-14 16:20:58 +00:00
* GPIO :
2020-11-15 09:23:40 +00:00
* You can use io pins 13 and 12 for input or output ( but 12 must not be high at boot )
* pin 16 is used for psram but you may get away with using it as input for a button etc .
2020-12-12 11:56:48 +00:00
* You could also use pins 1 & 3 if you do not use Serial ( disable serialDebug in the settings below )
2020-11-15 09:23:40 +00:00
* Pins 14 , 2 & 15 should be ok to use if you are not using an SD Card
* More info : https : //randomnerdtutorials.com/esp32-cam-ai-thinker-pinout/
2021-11-21 21:21:37 +00:00
*
2020-12-12 11:56:48 +00:00
* You can use a MCP23017 io expander chip to give 16 gpio lines by enabling ' useMCP23017 ' in the setup section and connecting
* the i2c pins to 12 and 13 on the esp32cam module . Note : this requires the adafruit MCP23017 library to be installed .
2021-11-21 21:21:37 +00:00
*
2020-11-13 15:17:38 +00:00
* Created using the Arduino IDE with ESP32 module installed , no additional libraries required
* ESP32 support for Arduino IDE : https : //raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
2021-11-21 21:21:37 +00:00
*
2020-09-26 14:35:33 +00:00
* Info on the esp32cam board : https : //randomnerdtutorials.com/esp32-cam-video-streaming-face-recognition-arduino-ide/
2021-11-21 21:21:37 +00:00
*
2020-09-27 06:21:17 +00:00
* To see a more advanced sketch along the same format as this one have a look at https : //github.com/alanesq/CameraWifiMotion
2020-12-14 07:01:24 +00:00
* which includes email support , FTP , OTA updates and motion detection
2021-11-21 21:21:37 +00:00
*
2021-04-25 06:22:34 +00:00
* Sending image to TFT display see : https : //www.survivingwithandroid.com/esp32-cam-tft-display-picture-st7735/
2021-11-21 21:21:37 +00:00
*
* esp32cam - demo is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the
2020-10-01 15:49:36 +00:00
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2021-11-21 21:21:37 +00:00
*
*
2020-09-26 14:35:33 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-12-04 17:08:13 +00:00
# if !defined ESP32
# error This sketch is only for an ESP32Cam module
# endif
2020-09-26 14:35:33 +00:00
2021-04-15 13:06:09 +00:00
// ---------------------------------------------------------------------------------------------------------
// Wifi Settings
2021-10-08 06:38:44 +00:00
# include <wifiSettings.h> // delete this line, un-comment the below two lines and enter your wifi details
2021-04-15 13:06:09 +00:00
2021-10-08 06:38:44 +00:00
//const char *SSID = "your_wifi_ssid";
//const char *PWD = "your_wifi_pwd";
2021-04-15 13:06:09 +00:00
// ---------------------------------------------------------------------------------------------------------
2021-11-21 21:21:37 +00:00
# include <Arduino.h> // required by PlatformIO
# include "esp_camera.h" // https://github.com/espressif/esp32-camera
// #include "camera_pins.h"
# include <WiFi.h>
# include <WebServer.h>
# include <HTTPClient.h> // used by requestWebPage()
# include "driver/ledc.h" // used to configure pwm on illumination led
// spiffs used to store images without an sd card
# include <SPIFFS.h>
# include <FS.h> // gives file access on spiffs
// forward declarations (required by PlatformIO)
bool initialiseCamera ( ) ;
bool cameraImageSettings ( ) ;
String localTime ( ) ;
void flashLED ( int reps ) ;
void showError ( int errorNo ) ;
byte storeImage ( ) ;
void handleRoot ( ) ;
void handlePhoto ( ) ;
bool handleImg ( ) ;
void handleNotFound ( ) ;
void readRGBImage ( ) ;
bool getNTPtime ( int sec ) ;
void handleStream ( ) ;
String requestWebPage ( String ip , String page , int port , int maxChars , String cuttoffText ) ;
void handleTest ( ) ;
void brightLed ( byte ledBrightness ) ;
void MessageRGB ( WiFiClient & client , String theText ) ;
2021-04-15 13:06:09 +00:00
2020-09-26 14:35:33 +00:00
// ---------------------------------------------------------------
2020-12-14 07:01:24 +00:00
// -SETTINGS
2020-09-26 14:35:33 +00:00
// ---------------------------------------------------------------
2020-12-12 11:56:48 +00:00
const char * stitle = " ESP32Cam-demo " ; // title of this sketch
2021-11-21 21:21:37 +00:00
const char * sversion = " 21Nov21 " ; // Sketch version
2021-04-15 13:06:09 +00:00
bool sendRGBfile = 0 ; // if set '/rgb' will send the rgb data as a file rather than display some on a HTML page
2020-09-26 14:35:33 +00:00
2021-08-13 13:28:18 +00:00
const bool serialDebug = 1 ; // show debug info. on serial port (1=enabled, disable if using pins 1 and 3 as gpio)
2020-12-12 11:56:48 +00:00
# define useMCP23017 0 // if MCP23017 IO expander chip is being used (on pins 12 and 13)
2020-09-26 14:35:33 +00:00
// Camera related
2020-12-12 11:56:48 +00:00
const bool flashRequired = 1 ; // If flash to be used when capturing image (1 = yes)
2021-11-21 21:21:37 +00:00
const framesize_t FRAME_SIZE_IMAGE = FRAMESIZE_VGA ; // Image resolution:
2020-11-13 15:17:38 +00:00
// default = "const framesize_t FRAME_SIZE_IMAGE = FRAMESIZE_VGA"
2021-11-21 21:21:37 +00:00
// 160x120 (QQVGA), 128x160 (QQVGA2), 176x144 (QCIF), 240x176 (HQVGA),
// 320x240 (QVGA), 400x296 (CIF), 640x480 (VGA, default), 800x600 (SVGA),
2020-09-26 14:35:33 +00:00
// 1024x768 (XGA), 1280x1024 (SXGA), 1600x1200 (UXGA)
2021-11-21 21:21:37 +00:00
# define PIXFORMAT PIXFORMAT_JPEG; // image format, Options = YUV422, GRAYSCALE, RGB565, JPEG, RGB888
2020-12-12 11:56:48 +00:00
int cameraImageExposure = 0 ; // Camera exposure (0 - 1200) If gain and exposure both set to zero then auto adjust is enabled
int cameraImageGain = 0 ; // Image gain (0 - 30)
2020-09-26 14:35:33 +00:00
2020-12-12 11:56:48 +00:00
const int TimeBetweenStatus = 600 ; // speed of flashing system running ok status light (milliseconds)
2020-09-26 14:35:33 +00:00
2020-12-12 11:56:48 +00:00
const int indicatorLED = 33 ; // onboard small LED pin (33)
2020-09-26 14:35:33 +00:00
2021-10-08 06:38:44 +00:00
// Bright LED
const int brightLED = 4 ; // onboard Illumination/flash LED pin (4)
int brightLEDbrightness = 0 ; // initial brightness (0 - 255)
const int ledFreq = 5000 ; // PWM settings
const int ledChannel = 15 ; // needs to be 14 or 15 with esp32cam (timer3?)
2021-11-21 21:21:37 +00:00
const int ledRresolution = 8 ;
2020-09-26 14:35:33 +00:00
2020-11-13 15:17:38 +00:00
const int iopinA = 13 ; // general io pin 13
const int iopinB = 12 ; // general io pin 12 (must not be high at boot)
2020-12-12 11:56:48 +00:00
const int iopinC = 16 ; // input only pin 16 (used by PSRam but you may get away with using it for a button)
2021-11-21 21:21:37 +00:00
2020-09-27 14:59:29 +00:00
const int serialSpeed = 115200 ; // Serial data speed to use
2020-09-27 07:38:25 +00:00
2020-12-14 07:01:24 +00:00
// NTP - Internet time
2021-04-15 13:06:09 +00:00
const char * ntpServer = " pool.ntp.org " ;
2021-01-05 11:56:34 +00:00
const char * TZ_INFO = " GMT+0BST-1,M3.5.0/01:00:00,M10.5.0/02:00:00 " ; // enter your time zone (https://remotemonitoringsystems.ca/time-zone-abbreviations.php)
long unsigned lastNTPtime ;
tm timeinfo ;
time_t now ;
2021-11-21 21:21:37 +00:00
2020-10-01 06:39:39 +00:00
// camera settings (for the standard - OV2640 - CAMERA_MODEL_AI_THINKER)
2021-04-25 06:22:34 +00:00
// see: https://randomnerdtutorials.com/esp32-cam-camera-pin-gpios/
// set camera resolution etc. in 'initialiseCamera()' and 'cameraImageSettings()'
2020-09-26 14:35:33 +00:00
# define CAMERA_MODEL_AI_THINKER
2020-11-13 15:17:38 +00:00
# define PWDN_GPIO_NUM 32 // power to camera (on/off)
2020-09-26 14:35:33 +00:00
# define RESET_GPIO_NUM -1 // -1 = not used
# define XCLK_GPIO_NUM 0
# define SIOD_GPIO_NUM 26 // i2c sda
# define SIOC_GPIO_NUM 27 // i2c scl
# 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 // vsync_pin
# define HREF_GPIO_NUM 23 // href_pin
# define PCLK_GPIO_NUM 22 // pixel_clock_pin
2020-12-14 07:01:24 +00:00
2021-11-21 21:21:37 +00:00
// ******************************************************************************************************************
2020-12-14 07:01:24 +00:00
WebServer server ( 80 ) ; // serve web pages on port 80
2021-11-21 21:21:37 +00:00
// Used to disable brownout detection
# include "soc/soc.h"
# include "soc/rtc_cntl_reg.h"
2020-12-14 07:01:24 +00:00
// sd-card
# include "SD_MMC.h" // sd card - see https://randomnerdtutorials.com/esp32-cam-take-photo-save-microsd-card/
2021-11-21 21:21:37 +00:00
# include <SPI.h>
# include <FS.h> // gives file access
2020-12-14 07:01:24 +00:00
# define SD_CS 5 // sd chip select pin = 5
// MCP23017 IO expander on pins 12 and 13 (optional)
# if useMCP23017 == 1
# include <Wire.h>
# include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp ;
// Wire.setClock(1700000); // set frequency to 1.7mhz
# endif
2021-11-21 21:21:37 +00:00
2020-12-14 07:01:24 +00:00
// 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
String spiffsFilename = " /image.jpg " ; // image name to use when storing in spiffs
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
// ******************************************************************************************************************
// ---------------------------------------------------------------
// -SETUP SETUP SETUP SETUP SETUP SETUP
// ---------------------------------------------------------------
void setup ( ) {
2021-11-21 21:21:37 +00:00
2020-12-10 08:10:18 +00:00
if ( serialDebug ) {
2021-11-21 21:21:37 +00:00
Serial . begin ( serialSpeed ) ; // Start serial communication
2021-10-08 06:38:44 +00:00
// Serial.setDebugOutput(true);
2021-11-21 21:21:37 +00:00
2020-12-10 08:10:18 +00:00
Serial . println ( " \n \n \n " ) ; // line feeds
Serial . println ( " ----------------------------------- " ) ;
2021-11-21 21:21:37 +00:00
Serial . printf ( " Starting - %s - %s \n " , stitle , sversion ) ;
2020-12-10 08:10:18 +00:00
Serial . println ( " ----------------------------------- " ) ;
2021-04-15 13:06:09 +00:00
// Serial.print("Reset reason: " + ESP.getResetReason());
2020-12-10 08:10:18 +00:00
}
2020-09-26 14:35:33 +00:00
2020-10-01 06:39:39 +00:00
WRITE_PERI_REG ( RTC_CNTL_BROWN_OUT_REG , 0 ) ; // Turn-off the 'brownout detector'
2020-09-26 14:35:33 +00:00
2020-12-14 07:01:24 +00:00
// small indicator led on rear of esp32cam board
2020-09-27 06:21:17 +00:00
pinMode ( indicatorLED , OUTPUT ) ;
digitalWrite ( indicatorLED , HIGH ) ;
2020-09-26 14:35:33 +00:00
// Connect to wifi
2020-09-27 06:21:17 +00:00
digitalWrite ( indicatorLED , LOW ) ; // small indicator led on
2020-12-10 08:10:18 +00:00
if ( serialDebug ) {
Serial . print ( " \n Connecting to " ) ;
2021-04-15 13:06:09 +00:00
Serial . print ( SSID ) ;
2020-12-10 08:10:18 +00:00
Serial . print ( " \n " ) ;
}
2021-04-15 13:06:09 +00:00
WiFi . begin ( SSID , PWD ) ;
2020-09-26 14:35:33 +00:00
while ( WiFi . status ( ) ! = WL_CONNECTED ) {
delay ( 500 ) ;
2020-12-10 08:10:18 +00:00
if ( serialDebug ) Serial . print ( " . " ) ;
}
if ( serialDebug ) {
Serial . print ( " \n WiFi connected, " ) ;
Serial . print ( " IP address: " ) ;
Serial . println ( WiFi . localIP ( ) ) ;
2020-09-26 14:35:33 +00:00
}
2020-11-13 15:17:38 +00:00
server . begin ( ) ; // start web server
2020-10-01 06:39:39 +00:00
digitalWrite ( indicatorLED , HIGH ) ; // small indicator led off
2020-09-26 14:35:33 +00:00
2020-10-01 06:39:39 +00:00
// define the web pages (i.e. call these procedures when url is requested)
server . on ( " / " , handleRoot ) ; // root page
server . on ( " /stream " , handleStream ) ; // stream live video
server . on ( " /photo " , handlePhoto ) ; // save image to sd card
server . on ( " /img " , handleImg ) ; // show image from sd card
2020-11-13 15:17:38 +00:00
server . on ( " /rgb " , readRGBImage ) ; // demo converting image to RGB
2020-11-14 16:20:58 +00:00
server . on ( " /test " , handleTest ) ; // Testing procedure
2020-10-01 06:39:39 +00:00
server . onNotFound ( handleNotFound ) ; // invalid url requested
2020-09-26 14:35:33 +00:00
2020-12-14 07:01:24 +00:00
// NTP - internet time
2021-01-05 11:56:34 +00:00
if ( serialDebug ) Serial . println ( " \n Getting real time (NTP) " ) ;
configTime ( 0 , 0 , ntpServer ) ;
setenv ( " TZ " , TZ_INFO , 1 ) ;
if ( getNTPtime ( 10 ) ) { // wait up to 10 sec to sync
} else {
if ( serialDebug ) Serial . println ( " Time not set " ) ;
2020-12-14 07:01:24 +00:00
}
2021-01-05 11:56:34 +00:00
lastNTPtime = time ( & now ) ;
2020-12-14 07:01:24 +00:00
2020-09-26 14:35:33 +00:00
// set up camera
2020-12-10 08:10:18 +00:00
if ( serialDebug ) Serial . print ( ( " \n Initialising camera: " ) ) ;
2021-04-25 06:22:34 +00:00
if ( initialiseCamera ( ) ) {
2020-12-10 08:10:18 +00:00
if ( serialDebug ) Serial . println ( " OK " ) ;
}
2020-09-26 14:35:33 +00:00
else {
2020-12-10 08:10:18 +00:00
if ( serialDebug ) Serial . println ( " Error! " ) ;
2020-10-01 06:39:39 +00:00
showError ( 2 ) ; // critical error so stop and flash led
2020-09-26 14:35:33 +00:00
}
2020-12-10 08:10:18 +00:00
// Spiffs - for storing images without an sd card
// see: https://circuits4you.com/2018/01/31/example-of-esp8266-flash-file-system-spiffs/
if ( ! SPIFFS . begin ( true ) ) {
if ( serialDebug ) Serial . println ( ( " An Error has occurred while mounting SPIFFS - restarting " ) ) ;
delay ( 5000 ) ;
ESP . restart ( ) ; // restart and try again
delay ( 5000 ) ;
} else {
2021-10-08 06:38:44 +00:00
// SPIFFS.format(); // wipe spiffs
2020-12-10 08:10:18 +00:00
if ( serialDebug ) {
Serial . print ( ( " SPIFFS mounted successfully: " ) ) ;
Serial . printf ( " total bytes: %d , used: %d \n " , SPIFFS . totalBytes ( ) , SPIFFS . usedBytes ( ) ) ;
}
}
2020-10-01 06:39:39 +00:00
// SD Card - if one is detected set 'sdcardPresent' High
2021-11-21 21:21:37 +00:00
if ( ! SD_MMC . begin ( " /sdcard " , true ) ) { // if loading sd card fails
2020-09-30 10:50:35 +00:00
// note: ('/sdcard", true)' = 1bit mode - see: https://www.reddit.com/r/esp32/comments/d71es9/a_breakdown_of_my_experience_trying_to_talk_to_an/
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . println ( " No SD Card detected " ) ;
2020-10-01 06:39:39 +00:00
sdcardPresent = 0 ; // flag no sd card available
2020-09-26 14:35:33 +00:00
} else {
uint8_t cardType = SD_MMC . cardType ( ) ;
2020-10-01 06:39:39 +00:00
if ( cardType = = CARD_NONE ) { // if invalid card found
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . println ( " SD Card type detect failed " ) ;
2020-10-01 06:39:39 +00:00
sdcardPresent = 0 ; // flag no sd card available
2020-09-26 14:35:33 +00:00
} else {
2020-09-27 06:21:17 +00:00
// valid sd card detected
2020-09-26 14:35:33 +00:00
uint16_t SDfreeSpace = ( uint64_t ) ( SD_MMC . totalBytes ( ) - SD_MMC . usedBytes ( ) ) / ( 1024 * 1024 ) ;
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . printf ( " SD Card found, free space = %dMB \n " , SDfreeSpace ) ;
2020-10-01 06:39:39 +00:00
sdcardPresent = 1 ; // flag sd card available
2020-09-26 14:35:33 +00:00
}
}
2020-10-01 06:39:39 +00:00
fs : : FS & fs = SD_MMC ; // sd card file system
2020-09-26 14:35:33 +00:00
2020-12-14 07:01:24 +00:00
// discover the number of image files already stored in '/img' folder of the sd card and set image file counter accordingly
2020-09-30 10:50:35 +00:00
imageCounter = 0 ;
2020-09-26 14:35:33 +00:00
if ( sdcardPresent ) {
2020-10-01 06:39:39 +00:00
int tq = fs . mkdir ( " /img " ) ; // create the '/img' folder on sd card (in case it is not already there)
2020-12-10 08:10:18 +00:00
if ( ! tq ) {
if ( serialDebug ) Serial . println ( " Unable to create IMG folder on sd card " ) ;
}
2020-09-30 10:50:35 +00:00
// open the image folder and step through all files in it
2021-11-21 21:21:37 +00:00
File root = fs . open ( " /img " ) ;
2020-09-30 10:50:35 +00:00
while ( true )
{
File entry = root . openNextFile ( ) ; // open next file in the folder
if ( ! entry ) break ; // if no more files in the folder
imageCounter + + ; // increment image counter
entry . close ( ) ;
}
root . close ( ) ;
2020-12-10 08:10:18 +00:00
if ( serialDebug ) Serial . printf ( " Image file count = %d \n " , imageCounter ) ;
2020-09-26 14:35:33 +00:00
}
2021-11-21 21:21:37 +00:00
// define i/o pins
2020-10-01 06:39:39 +00:00
pinMode ( indicatorLED , OUTPUT ) ; // defined again as sd card config can reset it
digitalWrite ( indicatorLED , HIGH ) ; // led off = High
2020-11-14 07:52:27 +00:00
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)
2020-11-14 16:20:58 +00:00
pinMode ( iopinC , INPUT ) ; // pin 16 - free input only pin
2020-09-26 14:35:33 +00:00
2020-12-12 11:56:48 +00:00
// MCP23017 io expander (requires adafruit MCP23017 library)
# if useMCP23017 == 1
Wire . begin ( 12 , 13 ) ; // use pins 12 and 13 for i2c
mcp . begin ( & Wire ) ; // use default address 0
mcp . pinMode ( 0 , OUTPUT ) ; // Define GPA0 (physical pin 21) as output pin
mcp . pinMode ( 8 , INPUT ) ; // Define GPB0 (physical pin 1) as input pin
mcp . pullUp ( 8 , HIGH ) ; // turn on a 100K pullup internally
// change pin state with mcp.digitalWrite(0, HIGH);
// read pin state with mcp.digitalRead(8)
# endif
2021-10-08 06:38:44 +00:00
// set up bright LED (flash)
ledcSetup ( ledChannel , ledFreq , ledRresolution ) ;
ledcAttachPin ( brightLED , ledChannel ) ;
brightLed ( 0 ) ; // change bright LED
2020-11-26 17:40:39 +00:00
2021-08-13 13:28:18 +00:00
// startup complete
if ( serialDebug ) Serial . println ( " \n Setup complete... " ) ;
2021-10-08 06:38:44 +00:00
brightLed ( 64 ) ; // change bright LED
2021-08-13 13:28:18 +00:00
delay ( 200 ) ;
2021-10-08 06:38:44 +00:00
brightLed ( 0 ) ; // change bright LED
2020-09-26 14:35:33 +00:00
2021-08-13 13:28:18 +00:00
} // setup
2020-09-26 14:35:33 +00:00
2021-10-08 06:38:44 +00:00
// change bright LED illumination level
void brightLed ( byte ledBrightness ) {
brightLEDbrightness = ledBrightness ; // store setting
ledcWrite ( ledChannel , ledBrightness ) ; // change LED brightness (0 - 255)
}
2020-09-26 14:35:33 +00:00
// ******************************************************************************************************************
// ----------------------------------------------------------------
// -LOOP LOOP LOOP LOOP LOOP LOOP LOOP
// ----------------------------------------------------------------
void loop ( ) {
2020-09-27 07:38:25 +00:00
server . handleClient ( ) ; // handle any incoming web page requests
2020-09-26 14:35:33 +00:00
2020-09-27 06:21:17 +00:00
2021-11-21 21:21:37 +00:00
2020-11-14 07:52:27 +00:00
// <<< YOUR CODE HERE >>>
2020-09-27 07:38:25 +00:00
2020-12-14 07:01:24 +00:00
2020-11-14 07:52:27 +00:00
// // demo to Capture an image and save to sd card every 5 seconds (i.e. time lapse)
2021-11-21 21:21:37 +00:00
// if ( ((unsigned long)(millis() - lastCamera) >= 5000) && sdcardPresent ) {
2020-09-27 07:38:25 +00:00
// lastCamera = millis(); // reset timer
// storeImage(); // save an image to sd card
// }
2021-11-21 21:21:37 +00:00
2020-11-13 15:17:38 +00:00
// flash status LED to show sketch is running ok
2021-11-21 21:21:37 +00:00
if ( ( unsigned long ) ( millis ( ) - lastStatus ) > = TimeBetweenStatus ) {
2020-09-26 14:35:33 +00:00
lastStatus = millis ( ) ; // reset timer
digitalWrite ( indicatorLED , ! digitalRead ( indicatorLED ) ) ; // flip indicator led status
}
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
} // loop
// ******************************************************************************************************************
// ----------------------------------------------------------------
2021-04-25 06:22:34 +00:00
// Initialise the camera
2020-09-30 10:50:35 +00:00
// ----------------------------------------------------------------
2021-04-25 06:22:34 +00:00
// returns TRUE if successful
2020-09-30 10:50:35 +00:00
2021-04-25 06:22:34 +00:00
bool initialiseCamera ( ) {
2021-11-21 21:21:37 +00:00
2021-04-25 06:22:34 +00:00
camera_config_t config ;
2021-11-21 21:21:37 +00:00
2020-09-30 10:50:35 +00:00
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 ; // XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
2021-08-13 13:28:18 +00:00
config . pixel_format = PIXFORMAT ; // Options = YUV422, GRAYSCALE, RGB565, JPEG, RGB888
2021-11-21 21:21:37 +00:00
config . frame_size = FRAME_SIZE_IMAGE ; // Image sizes: 160x120 (QQVGA), 128x160 (QQVGA2), 176x144 (QCIF), 240x176 (HQVGA), 320x240 (QVGA),
// 400x296 (CIF), 640x480 (VGA, default), 800x600 (SVGA), 1024x768 (XGA), 1280x1024 (SXGA),
2020-11-14 07:52:27 +00:00
// 1600x1200 (UXGA)
2021-04-25 06:22:34 +00:00
config . jpeg_quality = 10 ; // 0-63 lower number means higher quality
2020-09-30 10:50:35 +00:00
config . fb_count = 1 ; // if more than one, i2s runs in continuous mode. Use only with JPEG
2021-04-25 06:22:34 +00:00
// check the esp32cam board has a psram chip installed (extra memory used for storing captured images)
// Note: if not using "AI thinker esp32 cam" in the Arduino IDE, SPIFFS must be enabled
if ( ! psramFound ( ) ) {
if ( serialDebug ) Serial . println ( " Warning: No PSRam found so defaulting to image size 'CIF' " ) ;
config . frame_size = FRAMESIZE_CIF ;
}
2021-11-21 21:21:37 +00:00
2021-04-25 06:22:34 +00:00
//#if defined(CAMERA_MODEL_ESP_EYE)
// pinMode(13, INPUT_PULLUP);
// pinMode(14, INPUT_PULLUP);
2021-11-21 21:21:37 +00:00
//#endif
2020-09-30 10:50:35 +00:00
esp_err_t camerr = esp_camera_init ( & config ) ; // initialise the camera
2020-12-10 08:10:18 +00:00
if ( camerr ! = ESP_OK ) {
if ( serialDebug ) Serial . printf ( " ERROR: Camera init failed with error 0x%x " , camerr ) ;
}
2020-09-30 10:50:35 +00:00
2021-11-21 21:21:37 +00:00
cameraImageSettings ( ) ; // apply custom camera settings
2020-09-30 10:50:35 +00:00
return ( camerr = = ESP_OK ) ; // return boolean result of camera initialisation
}
// ******************************************************************************************************************
// ----------------------------------------------------------------
2020-12-14 07:01:24 +00:00
// -Change camera image settings
2020-09-26 14:35:33 +00:00
// ----------------------------------------------------------------
2020-11-14 07:52:27 +00:00
// Adjust image properties (brightness etc.)
2020-11-11 16:32:05 +00:00
// Defaults to auto adjustments if exposure and gain are both set to zero
2020-11-14 07:52:27 +00:00
// - Returns TRUE if successful
2021-01-05 11:56:34 +00:00
// BTW - some interesting info on exposure times here: https://github.com/raduprv/esp32-cam_ov2640-timelapse
2020-11-11 16:32:05 +00:00
2021-11-21 21:21:37 +00:00
bool cameraImageSettings ( ) {
sensor_t * s = esp_camera_sensor_get ( ) ;
// something to try?: if (s->id.PID == OV3660_PID)
2020-11-11 16:32:05 +00:00
if ( s = = NULL ) {
2020-12-10 08:10:18 +00:00
if ( serialDebug ) Serial . println ( " Error: problem reading camera sensor settings " ) ;
2020-11-11 16:32:05 +00:00
return 0 ;
2021-11-21 21:21:37 +00:00
}
2020-11-11 16:32:05 +00:00
2020-11-14 07:52:27 +00:00
// if both set to zero enable auto adjust
2021-11-21 21:21:37 +00:00
if ( cameraImageExposure = = 0 & & cameraImageGain = = 0 ) {
2020-11-11 16:32:05 +00:00
// enable auto adjust
2021-11-21 21:21:37 +00:00
s - > set_gain_ctrl ( s , 1 ) ; // auto gain on
s - > set_exposure_ctrl ( s , 1 ) ; // auto exposure on
2020-11-11 16:32:05 +00:00
s - > set_awb_gain ( s , 1 ) ; // Auto White Balance enable (0 or 1)
} else {
// Apply manual settings
2021-11-21 21:21:37 +00:00
s - > set_gain_ctrl ( s , 0 ) ; // auto gain off
2020-11-14 07:52:27 +00:00
s - > set_awb_gain ( s , 1 ) ; // Auto White Balance enable (0 or 1)
2021-11-21 21:21:37 +00:00
s - > set_exposure_ctrl ( s , 0 ) ; // auto exposure off
2020-11-11 16:32:05 +00:00
s - > set_agc_gain ( s , cameraImageGain ) ; // set gain manually (0 - 30)
s - > set_aec_value ( s , cameraImageExposure ) ; // set exposure manually (0-1200)
}
2020-09-26 14:35:33 +00:00
2020-11-11 16:32:05 +00:00
return 1 ;
} // cameraImageSettings
// // More camera settings available:
// // If you enable gain_ctrl or exposure_ctrl it will prevent a lot of the other settings having any effect
// // more info on settings here: https://randomnerdtutorials.com/esp32-cam-ov2640-camera-settings/
// s->set_gain_ctrl(s, 0); // auto gain off (1 or 0)
// s->set_exposure_ctrl(s, 0); // auto exposure off (1 or 0)
// s->set_agc_gain(s, cameraImageGain); // set gain manually (0 - 30)
// s->set_aec_value(s, cameraImageExposure); // set exposure manually (0-1200)
2021-11-21 21:21:37 +00:00
// s->set_vflip(s, cameraImageInvert); // Invert image (0 or 1)
2020-11-11 16:32:05 +00:00
// s->set_quality(s, 10); // (0 - 63)
2021-11-21 21:21:37 +00:00
// s->set_gainceiling(s, GAINCEILING_32X); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128)
2020-11-11 16:32:05 +00:00
// s->set_brightness(s, cameraImageBrightness); // (-2 to 2) - set brightness
// s->set_lenc(s, 1); // lens correction? (1 or 0)
// s->set_saturation(s, 0); // (-2 to 2)
// s->set_contrast(s, cameraImageContrast); // (-2 to 2)
2021-11-21 21:21:37 +00:00
// s->set_sharpness(s, 0); // (-2 to 2)
2020-11-11 16:32:05 +00:00
// s->set_hmirror(s, 0); // (0 or 1) flip horizontally
// s->set_colorbar(s, 0); // (0 or 1) - show a testcard
// s->set_special_effect(s, 0); // (0 to 6?) apply special effect
// s->set_whitebal(s, 0); // white balance enable (0 or 1)
2021-11-21 21:21:37 +00:00
// s->set_awb_gain(s, 1); // Auto White Balance enable (0 or 1)
2020-11-11 16:32:05 +00:00
// s->set_wb_mode(s, 0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
// s->set_dcw(s, 0); // downsize enable? (1 or 0)?
// s->set_raw_gma(s, 1); // (1 or 0)
// s->set_aec2(s, 0); // automatic exposure sensor? (0 or 1)
// s->set_ae_level(s, 0); // auto exposure levels (-2 to 2)
// s->set_bpc(s, 0); // black pixel correction
// s->set_wpc(s, 0); // white pixel correction
// ******************************************************************************************************************
// ----------------------------------------------------------------
// Misc small procedures
// ----------------------------------------------------------------
2020-09-26 14:35:33 +00:00
2020-10-01 06:39:39 +00:00
2020-12-14 07:01:24 +00:00
// returns the current real time as a String
// see: https://randomnerdtutorials.com/esp32-date-time-ntp-client-server-arduino/
String localTime ( ) {
struct tm timeinfo ;
char ttime [ 40 ] ;
if ( ! getLocalTime ( & timeinfo ) ) return " Failed to obtain time " ;
strftime ( ttime , 40 , " %A, %B %d %Y %H:%M:%S " , & timeinfo ) ;
return ttime ;
}
2020-10-01 06:39:39 +00:00
// flash the indicator led 'reps' number of times
2020-09-26 14:35:33 +00:00
void flashLED ( int reps ) {
for ( int x = 0 ; x < reps ; x + + ) {
digitalWrite ( indicatorLED , LOW ) ;
delay ( 1000 ) ;
digitalWrite ( indicatorLED , HIGH ) ;
delay ( 500 ) ;
}
}
2020-10-01 06:39:39 +00:00
// critical error - stop sketch and continually flash error code on indicator led
2020-09-26 14:35:33 +00:00
void showError ( int errorNo ) {
while ( 1 ) {
flashLED ( errorNo ) ;
delay ( 4000 ) ;
}
}
// ******************************************************************************************************************
// ----------------------------------------------------------------
2020-12-10 08:10:18 +00:00
// Capture image from camera and save to spiffs or sd card
2020-09-26 14:35:33 +00:00
// ----------------------------------------------------------------
2020-12-10 11:08:04 +00:00
// returns 0 if failed, 1 if stored in spiffs, 2 if stored on sd card
2020-09-26 14:35:33 +00:00
2020-12-10 08:10:18 +00:00
byte storeImage ( ) {
2020-09-26 14:35:33 +00:00
fs : : FS & fs = SD_MMC ; // sd card file system
2020-12-12 11:56:48 +00:00
// capture the image from camera
2021-10-08 06:38:44 +00:00
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
if ( flashRequired ) brightLed ( currentBrightness ) ; // change LED brightness back to previous state
2020-12-12 11:56:48 +00:00
if ( ! fb ) {
if ( serialDebug ) Serial . println ( " Error: Camera capture failed " ) ;
flashLED ( 3 ) ; // stop and display error code on LED
// return 0
}
2020-12-10 08:10:18 +00:00
2020-12-12 11:56:48 +00:00
// save image to Spiffs
2020-12-10 08:10:18 +00:00
if ( ! sdcardPresent ) {
2020-12-14 07:01:24 +00:00
if ( serialDebug ) Serial . println ( " Storing image to spiffs only " ) ;
2020-12-10 08:10:18 +00:00
SPIFFS . remove ( spiffsFilename ) ; // delete old image file if it exists
File file = SPIFFS . open ( spiffsFilename , FILE_WRITE ) ;
if ( ! file ) {
if ( serialDebug ) Serial . println ( " Failed to create file in Spiffs " ) ;
return 0 ;
}
else {
2021-11-21 21:21:37 +00:00
if ( file . write ( fb - > buf , fb - > len ) ) {
2020-12-10 08:10:18 +00:00
if ( serialDebug ) {
Serial . print ( " The picture has been saved as " + spiffsFilename ) ;
Serial . print ( " - Size: " ) ;
Serial . print ( file . size ( ) ) ;
Serial . println ( " bytes " ) ;
}
} else {
2020-12-14 07:01:24 +00:00
if ( serialDebug ) Serial . println ( " Error: writing image to spiffs...will format and try again " ) ;
2020-12-12 11:56:48 +00:00
if ( ! SPIFFS . format ( ) ) {
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . println ( " Error: Unable to format Spiffs " ) ;
2020-12-14 07:01:24 +00:00
return 0 ;
2020-12-12 11:56:48 +00:00
}
2020-12-10 08:10:18 +00:00
file = SPIFFS . open ( spiffsFilename , FILE_WRITE ) ;
if ( ! file . write ( fb - > buf , fb - > len ) ) {
if ( serialDebug ) Serial . println ( " Error: Still unable to write image to Spiffs " ) ;
return 0 ;
}
}
2021-11-21 21:21:37 +00:00
file . close ( ) ;
2020-12-10 08:10:18 +00:00
}
}
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
// save the image to sd card
2020-12-10 08:10:18 +00:00
if ( sdcardPresent ) {
2020-12-12 11:56:48 +00:00
if ( serialDebug ) Serial . printf ( " Storing image #%d to sd card \n " , imageCounter ) ;
2020-12-10 08:10:18 +00:00
String SDfilename = " /img/ " + String ( imageCounter + 1 ) + " .jpg " ; // build the image file name
File file = fs . open ( SDfilename , FILE_WRITE ) ; // create file on sd card
if ( ! file ) {
if ( serialDebug ) Serial . println ( " Error: Failed to create file on sd-card: " + SDfilename ) ;
2020-12-12 11:56:48 +00:00
flashLED ( 4 ) ; // stop and display error code on LED
2020-12-10 08:10:18 +00:00
// return 0
} else {
if ( file . write ( fb - > buf , fb - > len ) ) { // File created ok so save image to it
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . println ( " Image saved to sd card " ) ;
2020-12-10 08:10:18 +00:00
imageCounter + + ; // increment image counter
} else {
if ( serialDebug ) Serial . println ( " Error: failed to save image to sd card " ) ;
2020-12-12 11:56:48 +00:00
flashLED ( 4 ) ; // stop and display error code on LED
2020-12-10 08:10:18 +00:00
// return 0;
}
2020-12-10 11:08:04 +00:00
file . close ( ) ; // close image file on sd card
2020-09-26 14:35:33 +00:00
}
}
2021-11-21 21:21:37 +00:00
2020-12-10 08:10:18 +00:00
esp_camera_fb_return ( fb ) ; // return frame so memory can be released
2021-11-21 21:21:37 +00:00
if ( sdcardPresent ) return 2 ; // saved to sd card
2020-12-10 11:08:04 +00:00
else return 1 ; // saved in spiffs
2020-09-26 14:35:33 +00:00
} // storeImage
// ******************************************************************************************************************
// ----------------------------------------------------------------
// -root web page requested i.e. http://x.x.x.x/
// ----------------------------------------------------------------
2020-12-14 07:01:24 +00:00
// web page with control buttons, links etc.
2020-09-26 14:35:33 +00:00
void handleRoot ( ) {
2021-01-05 11:56:34 +00:00
getNTPtime ( 2 ) ; // refresh current time from NTP server
2020-09-30 10:50:35 +00:00
WiFiClient client = server . client ( ) ; // open link with client
2020-09-26 14:35:33 +00:00
2020-10-01 06:39:39 +00:00
// log the page request including clients IP address
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
2020-09-26 14:35:33 +00:00
IPAddress cip = client . remoteIP ( ) ;
2020-10-01 06:39:39 +00:00
Serial . printf ( " Root page requested from: %d.%d.%d.%d \n " , cip [ 0 ] , cip [ 1 ] , cip [ 2 ] , cip [ 3 ] ) ;
2020-09-30 10:50:35 +00:00
}
2020-09-26 14:35:33 +00:00
2020-10-01 06:39:39 +00:00
2020-10-01 15:49:36 +00:00
// Action any button presses or settings entered on web page
2020-09-27 07:38:25 +00:00
2020-09-30 10:50:35 +00:00
// if button1 was pressed (toggle io pin A)
2021-11-21 21:21:37 +00:00
// Note: if using an input box etc. you would read the value with the command: String Bvalue = server.arg("demobutton1");
2020-09-30 10:50:35 +00:00
if ( server . hasArg ( " button1 " ) ) {
digitalWrite ( iopinA , ! digitalRead ( iopinA ) ) ; // toggle output pin on/off
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . println ( " Button 1 pressed " ) ;
2020-09-30 10:50:35 +00:00
}
2021-11-21 21:21:37 +00:00
2020-09-30 10:50:35 +00:00
// if button2 was pressed (toggle io pin B)
if ( server . hasArg ( " button2 " ) ) {
digitalWrite ( iopinB , ! digitalRead ( iopinB ) ) ; // toggle output pin on/off
2020-12-02 12:07:04 +00:00
if ( serialDebug ) Serial . println ( " Button 2 pressed " ) ;
2020-09-30 10:50:35 +00:00
}
2021-11-21 21:21:37 +00:00
2020-09-30 10:50:35 +00:00
// if button3 was pressed (toggle flash LED)
if ( server . hasArg ( " button3 " ) ) {
2021-10-08 06:38:44 +00:00
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
2020-12-02 12:07:04 +00:00
if ( serialDebug ) Serial . println ( " Button 3 pressed " ) ;
2020-09-30 10:50:35 +00:00
}
2020-09-26 14:35:33 +00:00
2020-10-01 15:49:36 +00:00
// if exposure was adjusted - cameraImageExposure
if ( server . hasArg ( " exp " ) ) {
String Tvalue = server . arg ( " exp " ) ; // read value
if ( Tvalue ! = NULL ) {
int val = Tvalue . toInt ( ) ;
2021-11-21 21:21:37 +00:00
if ( val > = 0 & & val < = 1200 & & val ! = cameraImageExposure ) {
2020-12-02 12:07:04 +00:00
if ( serialDebug ) Serial . printf ( " Exposure changed to %d \n " , val ) ;
2020-10-01 15:49:36 +00:00
cameraImageExposure = val ;
cameraImageSettings ( ) ; // Apply camera image settings
}
}
}
// if image gain was adjusted - cameraImageGain
if ( server . hasArg ( " gain " ) ) {
String Tvalue = server . arg ( " gain " ) ; // read value
if ( Tvalue ! = NULL ) {
int val = Tvalue . toInt ( ) ;
2021-11-21 21:21:37 +00:00
if ( val > = 0 & & val < = 31 & & val ! = cameraImageGain ) {
2020-12-02 12:07:04 +00:00
if ( serialDebug ) Serial . printf ( " Gain changed to %d \n " , val ) ;
2020-10-01 15:49:36 +00:00
cameraImageGain = val ;
cameraImageSettings ( ) ; // Apply camera image settings
}
}
}
2020-09-27 07:38:25 +00:00
2020-09-30 10:50:35 +00:00
// html header
client . write ( " <!DOCTYPE html> <html lang='en'> <head> <title>root</title> </head> <body> \n " ) ; // basic html header
2020-10-01 15:49:36 +00:00
client . write ( " <FORM action='/' method='post'> \n " ) ; // used by the buttons in the html (action = the web page to send it to
2020-09-30 10:50:35 +00:00
2020-09-27 07:38:25 +00:00
// --------------------------------------------------------------------
// html main body
2021-11-21 21:21:37 +00:00
// Info on the arduino ethernet library: https://www.arduino.cc/en/Reference/Ethernet
2020-09-30 10:50:35 +00:00
// Info in HTML: https://www.w3schools.com/html/
2020-09-27 07:38:25 +00:00
// Info on Javascript (can be inserted in to the HTML): https://www.w3schools.com/js/default.asp
2020-09-30 10:50:35 +00:00
// Verify your HTML is valid: https://validator.w3.org/
2021-11-21 21:21:37 +00:00
2020-09-27 07:38:25 +00:00
client . write ( " <h1>Hello from ESP32Cam</h1> \n " ) ;
2020-09-26 14:35:33 +00:00
2020-09-27 09:20:51 +00:00
// sd card details
2021-11-21 21:21:37 +00:00
if ( sdcardPresent ) client . printf ( " <p>SD Card detected - %d images stored</p> \n " , imageCounter ) ;
2020-09-27 09:20:51 +00:00
else client . write ( " <p>No SD Card detected</p> \n " ) ;
// io pin details
2020-11-14 16:20:58 +00:00
if ( digitalRead ( iopinA ) = = LOW ) client . write ( " <p>Output Pin 13 is Low</p> \n " ) ;
else client . write ( " <p>Output Pin 13 is High</p> \n " ) ;
2021-11-21 21:21:37 +00:00
2020-11-14 16:20:58 +00:00
if ( digitalRead ( iopinB ) = = LOW ) client . write ( " <p>Output Pin 12 is Low</p> \n " ) ;
else client . write ( " <p>Output Pin 12 is High</p> \n " ) ;
2021-11-21 21:21:37 +00:00
2020-11-14 16:20:58 +00:00
if ( digitalRead ( iopinC ) = = LOW ) client . write ( " <p>Input Pin 16 is Low</p> \n " ) ;
else client . write ( " <p>Input Pin 16 is High</p> \n " ) ;
2020-09-27 07:38:25 +00:00
2020-12-10 11:08:04 +00:00
// illumination led brightness
client . printf ( " <p>Illumination led set to %d</p> \n " , illuminationLEDstatus ) ;
2020-12-14 07:01:24 +00:00
// Current real time
client . print ( " <p>Current time: " + localTime ( ) + " </p> \n " ) ;
2021-11-21 21:21:37 +00:00
// // touch input on the two gpio pins
2020-11-11 09:19:52 +00:00
// client.printf("<p>Touch on pin 12: %d </p>\n", touchRead(T5) );
// client.printf("<p>Touch on pin 13: %d </p>\n", touchRead(T4) );
2021-11-21 21:21:37 +00:00
// Control bottons
2020-09-27 07:38:25 +00:00
client . write ( " <input style='height: 35px;' name='button1' value='Toggle pin 13' type='submit'> \n " ) ;
client . write ( " <input style='height: 35px;' name='button2' value='Toggle pin 12' type='submit'> \n " ) ;
2020-11-11 09:19:52 +00:00
client . write ( " <input style='height: 35px;' name='button3' value='Toggle Flash' type='submit'><br> \n " ) ;
2020-09-27 07:38:25 +00:00
2020-10-01 15:49:36 +00:00
// Image setting controls
2020-11-11 09:19:52 +00:00
client . write ( " <br>CAMERA SETTINGS: \n " ) ;
2020-10-01 15:49:36 +00:00
client . printf ( " Exposure: <input type='number' style='width: 50px' name='exp' min='0' max='1200' value='%d'> \n " , cameraImageExposure ) ;
2021-11-21 21:21:37 +00:00
client . printf ( " Gain: <input type='number' style='width: 50px' name='gain' min='0' max='30' value='%d'> \n " , cameraImageGain ) ;
client . write ( " - Set both to zero for auto adjust<br> \n " ) ;
2020-11-11 09:19:52 +00:00
// links to the other pages available
client . write ( " <br>LINKS: \n " ) ;
2021-11-21 21:21:37 +00:00
client . write ( " <a href='/photo'>Capture an image</a> - \n " ) ;
client . write ( " <a href='/img'>View stored images</a> - \n " ) ;
client . write ( " <a href='/rgb'>Capture Image as raw RGB data</a> - \n " ) ;
client . write ( " <a href='/stream'>Live stream</a><br> \n " ) ;
2020-09-27 07:38:25 +00:00
// --------------------------------------------------------------------
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
// end html
2020-09-27 14:14:03 +00:00
client . write ( " </form></body></html> \n " ) ;
2020-09-26 14:35:33 +00:00
delay ( 3 ) ;
client . stop ( ) ;
} // handleRoot
// ******************************************************************************************************************
// ----------------------------------------------------------------
2020-12-10 08:10:18 +00:00
// -photo save to sd card/spiffs i.e. http://x.x.x.x/photo
2020-09-26 14:35:33 +00:00
// ----------------------------------------------------------------
2020-12-14 07:01:24 +00:00
// web page to capture an image from camera and save to spiffs or sd card
2020-09-26 14:35:33 +00:00
void handlePhoto ( ) {
WiFiClient client = server . client ( ) ; // open link with client
// log page request including clients IP address
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
2020-09-26 14:35:33 +00:00
IPAddress cip = client . remoteIP ( ) ;
2020-10-01 06:39:39 +00:00
Serial . printf ( " Photo requested from: %d.%d.%d.%d \n " , cip [ 0 ] , cip [ 1 ] , cip [ 2 ] , cip [ 3 ] ) ;
2020-09-30 10:50:35 +00:00
}
2020-09-26 14:35:33 +00:00
2020-12-10 08:10:18 +00:00
// save an image to sd card or spiffs
byte sRes = storeImage ( ) ; // save an image to sd card or spiffs (store sucess or failed flag - 0=fail, 1=spiffs only, 2=spiffs and sd card)
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
// html header
2020-09-30 10:50:35 +00:00
client . write ( " <!DOCTYPE html> <html lang='en'> <head> <title>photo</title> </head> <body> \n " ) ; // basic html header
2020-09-26 14:35:33 +00:00
// html body
2020-12-10 08:10:18 +00:00
if ( sRes = = 2 ) {
2020-10-18 13:26:49 +00:00
client . printf ( " <p>Image saved to sd card as image number %d </p> \n " , imageCounter ) ;
2021-11-21 21:21:37 +00:00
client . write ( " <a href='/img'>View Image</a> \n " ) ; // link to the image
2020-12-10 08:10:18 +00:00
} else if ( sRes = = 1 ) {
client . write ( " <p>Image saved in Spiffs</p> \n " ) ;
2021-11-21 21:21:37 +00:00
client . write ( " <a href='/img'>View Image</a> \n " ) ; // link to the image
2020-10-18 13:26:49 +00:00
} else {
2021-11-21 21:21:37 +00:00
client . write ( " <p>Error: Failed to save image to sd card</p> \n " ) ;
2020-10-18 13:26:49 +00:00
}
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
// end html
2020-09-30 10:50:35 +00:00
client . write ( " </body></html> \n " ) ;
2020-09-26 14:35:33 +00:00
delay ( 3 ) ;
client . stop ( ) ;
} // handlePhoto
2020-09-27 06:21:17 +00:00
// ----------------------------------------------------------------
2020-12-14 07:01:24 +00:00
// -display image stored on sd card or SPIFFS i.e. http://x.x.x.x/img?img=x
2020-09-27 06:21:17 +00:00
// ----------------------------------------------------------------
2020-12-12 11:56:48 +00:00
// Display a previously stored image, default image = most recent
2020-09-27 09:20:51 +00:00
// returns 1 if image displayed ok
bool handleImg ( ) {
2020-09-27 06:21:17 +00:00
WiFiClient client = server . client ( ) ; // open link with client
2021-11-21 21:21:37 +00:00
bool pRes = 0 ;
2020-09-30 10:50:35 +00:00
// log page request including clients IP address
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
2020-09-30 10:50:35 +00:00
IPAddress cip = client . remoteIP ( ) ;
2020-10-01 06:39:39 +00:00
Serial . printf ( " Image display requested from: %d.%d.%d.%d \n " , cip [ 0 ] , cip [ 1 ] , cip [ 2 ] , cip [ 3 ] ) ;
2020-09-30 10:50:35 +00:00
if ( imageCounter = = 0 ) Serial . println ( " Error: no images to display " ) ;
}
2021-11-21 21:21:37 +00:00
2020-09-27 06:21:17 +00:00
int imgToShow = imageCounter ; // default to showing most recent file
2021-11-21 21:21:37 +00:00
// get image number from url parameter
2020-09-27 06:21:17 +00:00
if ( server . hasArg ( " img " ) ) {
String Tvalue = server . arg ( " img " ) ; // read value
imgToShow = Tvalue . toInt ( ) ; // convert string to int
if ( imgToShow < 1 | | imgToShow > imageCounter ) imgToShow = imageCounter ; // validate image number
}
2020-12-10 08:10:18 +00:00
// if stored on sd card
if ( sdcardPresent ) {
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . printf ( " Displaying image #%d from sd card " , imgToShow ) ;
2020-12-10 08:10:18 +00:00
String tFileName = " /img/ " + String ( imgToShow ) + " .jpg " ;
fs : : FS & fs = SD_MMC ; // sd card file system
File timg = fs . open ( tFileName , " r " ) ;
if ( timg ) {
size_t sent = server . streamFile ( timg , " image/jpeg " ) ; // send the image
timg . close ( ) ;
2020-12-12 11:56:48 +00:00
pRes = 1 ; // flag sucess
2020-12-10 08:10:18 +00:00
} else {
if ( serialDebug ) Serial . println ( " Error: image file not found " ) ;
WiFiClient client = server . client ( ) ; // open link with client
client . write ( " <!DOCTYPE html> <html> <body> \n " ) ;
client . write ( " <p>Error: Image not found</p? \n " ) ;
delay ( 3 ) ;
client . stop ( ) ;
}
}
// if stored in SPIFFS
if ( ! sdcardPresent ) {
2021-11-21 21:21:37 +00:00
if ( serialDebug ) Serial . println ( " Displaying image from spiffs " ) ;
2020-12-10 08:10:18 +00:00
File f = SPIFFS . open ( spiffsFilename , " r " ) ; // read file from spiffs
if ( ! f ) {
if ( serialDebug ) Serial . println ( " Error reading " + spiffsFilename ) ;
}
else {
size_t sent = server . streamFile ( f , " image/jpeg " ) ; // send file to web page
if ( ! sent ) {
if ( serialDebug ) Serial . println ( " Error sending " + spiffsFilename ) ;
2020-12-12 11:56:48 +00:00
} else {
pRes = 1 ; // flag sucess
2020-12-10 08:10:18 +00:00
}
2021-11-21 21:21:37 +00:00
f . close ( ) ;
}
2020-09-27 06:21:17 +00:00
}
2020-12-12 11:56:48 +00:00
return pRes ;
2020-09-27 06:21:17 +00:00
} // handleImg
2020-09-26 14:35:33 +00:00
// ******************************************************************************************************************
// ----------------------------------------------------------------
// -invalid web page requested
// ----------------------------------------------------------------
2020-11-13 15:17:38 +00:00
// Note: shows a different way to send the HTML reply
2020-09-26 14:35:33 +00:00
void handleNotFound ( ) {
2020-10-01 06:39:39 +00:00
2020-11-13 15:17:38 +00:00
String tReply ;
2020-10-01 06:39:39 +00:00
// log page request
2020-12-10 08:10:18 +00:00
if ( serialDebug ) Serial . print ( " Invalid page requested " ) ;
2021-11-21 21:21:37 +00:00
2020-11-13 09:22:50 +00:00
tReply = " File Not Found \n \n " ;
tReply + = " URI: " ;
tReply + = server . uri ( ) ;
tReply + = " \n Method: " ;
tReply + = ( server . method ( ) = = HTTP_GET ) ? " GET " : " POST " ;
tReply + = " \n Arguments: " ;
tReply + = server . args ( ) ;
tReply + = " \n " ;
2020-09-26 14:35:33 +00:00
for ( uint8_t i = 0 ; i < server . args ( ) ; i + + ) {
2020-11-13 09:22:50 +00:00
tReply + = " " + server . argName ( i ) + " : " + server . arg ( i ) + " \n " ;
2020-09-26 14:35:33 +00:00
}
2020-11-13 09:22:50 +00:00
server . send ( 404 , " text/plain " , tReply ) ;
tReply = " " ; // clear variable
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
} // handleNotFound
2020-11-11 09:19:52 +00:00
// ******************************************************************************************************************
2020-11-11 10:18:52 +00:00
// ----------------------------------------------------------------
2020-11-13 15:17:38 +00:00
// -access image data as RGB - i.e. http://x.x.x.x/rgb
2020-11-11 10:18:52 +00:00
// ----------------------------------------------------------------
2020-12-14 07:01:24 +00:00
//Demonstration on how to access raw RGB data from the camera
2020-11-14 07:52:27 +00:00
// Notes:
2021-11-21 21:21:37 +00:00
// Set sendRGBfile to 1 in the settings at top of sketch to just send the rgb data as a file which can then be used with
2021-04-16 06:34:01 +00:00
// the Processing sketch: https://github.com/alanesq/esp32cam-demo/blob/master/Misc/displayRGB.pde
// otherwise a web page is displayed showing some sample rgb data usage.
2021-11-21 21:21:37 +00:00
// You may want to disable auto white balance when experimenting with RGB otherwise the camera is always trying to adjust the
2021-04-16 06:34:01 +00:00
// image colours to mainly white. (disable in the 'cameraImageSettings' procedure).
// It will fail on the highest resolution (1600x1200) as it requires more than the 4mb of available psram to store the data (1600x1200x3 bytes)
// I learned how to read the RGB data from: https://github.com/Makerfabs/Project_Touch-Screen-Camera/blob/master/Camera_v2/Camera_v2.ino
2020-11-11 09:19:52 +00:00
void readRGBImage ( ) {
2020-11-26 14:57:19 +00:00
uint32_t tTimer ; // used for timing operations
WiFiClient client = server . client ( ) ; // open link with client
2020-11-13 08:24:20 +00:00
2020-11-13 09:22:50 +00:00
// log page request including clients IP address
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
2020-11-13 09:22:50 +00:00
IPAddress cip = client . remoteIP ( ) ;
Serial . printf ( " RGB requested from: %d.%d.%d.%d \n " , cip [ 0 ] , cip [ 1 ] , cip [ 2 ] , cip [ 3 ] ) ;
2020-11-12 12:08:08 +00:00
}
2020-11-13 08:24:20 +00:00
2020-11-13 09:22:50 +00:00
// html header
2021-05-24 06:02:09 +00:00
if ( ! sendRGBfile ) client . write ( " <!DOCTYPE html> <html lang='en'> <head> <title>photo</title> </head> <body> \n " ) ; // basic html header
2021-11-21 21:21:37 +00:00
2020-11-26 14:57:19 +00:00
MessageRGB ( client , " LIVE IMAGE AS RGB DATA " ) ; // 'MessageRGB' sends the String to both serial port and web page
2021-11-21 21:21:37 +00:00
2020-11-26 14:57:19 +00:00
// ****** the main code for converting an image to RGB data *****
2021-11-21 21:21:37 +00:00
2020-11-26 14:57:19 +00:00
// capture a live image from camera (as a jpg)
2020-11-13 09:22:50 +00:00
camera_fb_t * fb = NULL ;
2020-11-26 14:57:19 +00:00
tTimer = millis ( ) ; // store time that image capture started
2021-11-21 21:21:37 +00:00
fb = esp_camera_fb_get ( ) ;
2020-11-26 14:57:19 +00:00
MessageRGB ( client , " Image capture took " + String ( millis ( ) - tTimer ) + " milliseconds " ) ; // report time it took to capture an image
2021-11-21 21:21:37 +00:00
if ( ! fb ) MessageRGB ( client , " -error capturing image from camera- " ) ;
MessageRGB ( client , " Image resolution= " + String ( fb - > width ) + " x " + String ( fb - > height ) ) ; // display image resolution
2020-11-26 14:57:19 +00:00
// allocate memory to store the rgb data (in psram, 3 bytes per pixel)
2020-11-13 09:22:50 +00:00
if ( ! psramFound ( ) ) MessageRGB ( client , " -error no psram found- " ) ;
MessageRGB ( client , " Free psram before rgb data stored = " + String ( heap_caps_get_free_size ( MALLOC_CAP_SPIRAM ) ) ) ;
2020-11-26 14:57:19 +00:00
void * ptrVal = NULL ; // create a pointer for memory location to store the data
uint32_t ARRAY_LENGTH = fb - > width * fb - > height * 3 ; // calculate memory required to store the RGB data (i.e. number of pixels in the jpg image x 3)
2020-11-13 09:22:50 +00:00
if ( heap_caps_get_free_size ( MALLOC_CAP_SPIRAM ) < ARRAY_LENGTH ) MessageRGB ( client , " -error: not enough free psram to store the rgb data- " ) ;
2021-11-21 21:21:37 +00:00
ptrVal = heap_caps_malloc ( ARRAY_LENGTH , MALLOC_CAP_SPIRAM ) ; // allocate memory space for the rgb data
2020-11-26 14:57:19 +00:00
uint8_t * rgb = ( uint8_t * ) ptrVal ; // create the 'rgb' array pointer to the allocated memory space
2020-11-13 09:22:50 +00:00
MessageRGB ( client , " Free psram after rgb data stored = " + String ( heap_caps_get_free_size ( MALLOC_CAP_SPIRAM ) ) ) ;
2021-11-21 21:21:37 +00:00
2020-11-26 14:57:19 +00:00
// convert the captured jpg image (fb) to rgb data (store in 'rgb' array)
tTimer = millis ( ) ; // store time that image conversion process started
2021-11-21 21:21:37 +00:00
bool jpeg_converted = fmt2rgb888 ( fb - > buf , fb - > len , PIXFORMAT_JPEG , rgb ) ;
if ( ! jpeg_converted ) MessageRGB ( client , " -error converting image to RGB- " ) ;
2020-11-26 14:57:19 +00:00
MessageRGB ( client , " Conversion from jpg to RGB took " + String ( millis ( ) - tTimer ) + " milliseconds " ) ; // report how long the conversion took
2020-11-13 08:24:20 +00:00
2021-11-21 21:21:37 +00:00
if ( sendRGBfile ) client . write ( rgb , ARRAY_LENGTH ) ; // send the rgb data as a file
2021-04-15 13:06:09 +00:00
2020-11-13 09:22:50 +00:00
// ****** examples of reading the resulting RGB data *****
2021-11-21 21:21:37 +00:00
2020-11-13 08:24:20 +00:00
// display some of the resulting data
2020-11-26 14:57:19 +00:00
uint32_t resultsToShow = 60 ; // how much data to display
2020-11-13 09:22:50 +00:00
MessageRGB ( client , " R , G , B " ) ;
for ( uint32_t i = 0 ; i < resultsToShow - 2 ; i + = 3 ) {
2020-11-26 14:57:19 +00:00
MessageRGB ( client , String ( rgb [ i + 2 ] ) + " , " + String ( rgb [ i + 1 ] ) + " , " + String ( rgb [ i + 0 ] ) ) ; // Red , Green , Blue
2020-11-14 07:52:27 +00:00
// // calculate the x and y coordinate of the current pixel
// uint16_t x = (i / 3) % fb->width;
// uint16_t y = floor( (i / 3) / fb->width);
2020-11-13 08:24:20 +00:00
}
2021-11-21 21:21:37 +00:00
2020-11-13 08:24:20 +00:00
// find the average values for each colour over entire image
uint32_t aRed = 0 ;
uint32_t aGreen = 0 ;
uint32_t aBlue = 0 ;
2020-11-26 14:57:19 +00:00
for ( uint32_t i = 0 ; i < ( ARRAY_LENGTH - 2 ) ; i + = 3 ) { // go through all data and add up totals
2020-11-13 08:24:20 +00:00
aBlue + = rgb [ i ] ;
aGreen + = rgb [ i + 1 ] ;
aRed + = rgb [ i + 2 ] ;
2021-11-21 21:21:37 +00:00
}
2020-11-26 14:57:19 +00:00
aRed = aRed / ( fb - > width * fb - > height ) ; // divide total by number of pixels to give the average value
2020-11-13 08:24:20 +00:00
aGreen = aGreen / ( fb - > width * fb - > height ) ;
aBlue = aBlue / ( fb - > width * fb - > height ) ;
2020-11-13 09:22:50 +00:00
MessageRGB ( client , " Average Blue = " + String ( aBlue ) ) ;
MessageRGB ( client , " Average Green = " + String ( aGreen ) ) ;
2021-11-21 21:21:37 +00:00
MessageRGB ( client , " Average Red = " + String ( aRed ) ) ;
2020-11-13 08:24:20 +00:00
2020-11-13 09:22:50 +00:00
// *******************************************************
// end html
2021-04-15 13:06:09 +00:00
if ( ! sendRGBfile ) client . write ( " </body></html> \n " ) ;
2020-11-13 09:22:50 +00:00
delay ( 3 ) ;
2021-11-21 21:21:37 +00:00
client . stop ( ) ;
2020-11-13 09:22:50 +00:00
2021-11-21 21:21:37 +00:00
// finished with the data so free up the memory space used in psram
esp_camera_fb_return ( fb ) ; // camera frame buffer
heap_caps_free ( ptrVal ) ; // rgb data
2020-11-11 09:19:52 +00:00
2020-11-11 16:32:05 +00:00
} // readRGBImage
2020-11-11 09:19:52 +00:00
2020-11-13 09:22:50 +00:00
// send line of text to both serial port and web page
void MessageRGB ( WiFiClient & client , String theText ) {
2021-11-21 21:21:37 +00:00
if ( ! sendRGBfile ) client . print ( theText + " <br> \n " ) ;
if ( serialDebug | | theText . indexOf ( " error " ) > 0 ) Serial . println ( theText ) ;
2020-11-13 09:22:50 +00:00
}
2021-01-05 11:56:34 +00:00
// ******************************************************************************************************************
2021-11-21 21:21:37 +00:00
2021-01-05 11:56:34 +00:00
// ----------------------------------------------------------------
// -get time from ntp server
// ----------------------------------------------------------------
bool getNTPtime ( int sec ) {
{
uint32_t start = millis ( ) ;
do {
time ( & now ) ;
localtime_r ( & now , & timeinfo ) ;
Serial . print ( " . " ) ;
2021-10-08 06:38:44 +00:00
delay ( 100 ) ;
2021-01-05 11:56:34 +00:00
} 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 ( ) ;
}
return true ;
}
2020-09-26 14:35:33 +00:00
// ******************************************************************************************************************
// ----------------------------------------------------------------
// -stream requested i.e. http://x.x.x.x/stream
// ----------------------------------------------------------------
2020-11-11 16:32:05 +00:00
// Sends cam stream - thanks to Uwe Gerlach for the code showing me how to do this
2020-09-26 14:35:33 +00:00
void handleStream ( ) {
WiFiClient client = server . client ( ) ; // open link with client
// log page request including clients IP address
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
2020-09-26 14:35:33 +00:00
IPAddress cip = client . remoteIP ( ) ;
2020-10-01 06:39:39 +00:00
Serial . printf ( " Video stream requested from: %d.%d.%d.%d \n " , cip [ 0 ] , cip [ 1 ] , cip [ 2 ] , cip [ 3 ] ) ;
2020-09-30 10:50:35 +00:00
}
2020-09-26 14:35:33 +00:00
// 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 \n Content-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
2021-11-21 21:21:37 +00:00
char buf [ 32 ] ;
2020-09-26 14:35:33 +00:00
int s ;
camera_fb_t * fb = NULL ;
2021-11-21 21:21:37 +00:00
// send html header
2020-09-26 14:35:33 +00:00
client . write ( HEADER , hdrLen ) ;
client . write ( BOUNDARY , bdrLen ) ;
// send live images until client disconnects
while ( true )
{
if ( ! client . connected ( ) ) break ;
2021-11-21 21:21:37 +00:00
fb = esp_camera_fb_get ( ) ; // capture live image
2020-09-26 14:35:33 +00:00
s = fb - > len ; // store size of image (i.e. buffer length)
client . write ( CTNTTYPE , cntLen ) ; // send content type html (i.e. jpg image)
2020-10-01 06:39:39 +00:00
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)
2020-09-26 14:35:33 +00:00
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
2020-10-01 06:39:39 +00:00
esp_camera_fb_return ( fb ) ; // return image so memory can be released
2020-09-26 14:35:33 +00:00
}
2021-11-21 21:21:37 +00:00
2020-12-02 12:07:04 +00:00
if ( serialDebug ) Serial . println ( " Video stream stopped " ) ;
2020-09-26 14:35:33 +00:00
delay ( 3 ) ;
client . stop ( ) ;
2021-11-21 21:21:37 +00:00
2020-09-26 14:35:33 +00:00
} // handleStream
2020-11-26 14:57:19 +00:00
2020-12-02 12:07:04 +00:00
// ******************************************************************************************************************
2020-11-26 17:40:39 +00:00
// ----------------------------------------------------------------
2020-12-02 12:07:04 +00:00
// request a web page
2020-11-26 17:40:39 +00:00
// ----------------------------------------------------------------
2021-11-21 21:21:37 +00:00
// @param ip ip address
// @param page web page to request
// @param port ip port to use (usually 80)
// @param maxChars maximum number of chars to receive
// @param cuttoffText ignore all in reply before this text
// @return the reply as a string
// Example usage: requestWebPage("192.168.1.166", "/log", 80, 600, "");
2020-12-14 07:01:24 +00:00
String requestWebPage ( String ip , String page , int port , int maxChars , String cuttoffText = " " ) {
2020-12-02 12:07:04 +00:00
2021-11-21 21:21:37 +00:00
uint32_t maxWaitTime = 3000 ; // max time to wait for reply (ms)
2020-12-02 12:07:04 +00:00
2020-12-14 07:01:24 +00:00
char received [ maxChars + 1 ] ; // temp store for incoming character data
2021-11-21 21:21:37 +00:00
int received_counter = 0 ; // counter of number of characters which have been received
2020-12-14 07:01:24 +00:00
2021-11-21 21:21:37 +00:00
if ( ! page . startsWith ( " / " ) ) page = " / " + page ; // make sure page begins with "/"
2020-11-26 17:40:39 +00:00
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
Serial . print ( " requesting web page: " ) ;
Serial . print ( ip ) ;
Serial . println ( page ) ;
}
2021-11-21 21:21:37 +00:00
2020-12-02 12:07:04 +00:00
WiFiClient client ;
2021-11-21 21:21:37 +00:00
// Connect to the site
if ( ! client . connect ( ip . c_str ( ) , port ) ) {
if ( serialDebug ) Serial . println ( " Web client connection failed " ) ;
2020-12-02 12:07:04 +00:00
return " web client connection failed " ;
2021-11-21 21:21:37 +00:00
}
2020-12-02 12:07:04 +00:00
if ( serialDebug ) Serial . println ( " Connected to host - sending request... " ) ;
2021-11-21 21:21:37 +00:00
2020-12-02 12:07:04 +00:00
// send request - A basic request looks something like: "GET /index.html HTTP/1.1\r\nHost: 192.168.0.4:8085\r\n\r\n"
2021-11-21 21:21:37 +00:00
client . println ( " GET " + page + " HTTP/1.1 " ) ;
client . println ( " Host: " + ip ) ;
client . println ( " User-Agent: arduino-ethernet " ) ;
client . println ( " Connection: close " ) ;
client . println ( ) ; // needed to end HTTP header
2020-12-02 12:07:04 +00:00
if ( serialDebug ) Serial . println ( " Request sent - waiting for reply... " ) ;
2021-11-21 21:21:37 +00:00
2020-12-14 07:01:24 +00:00
// Wait for a response
uint32_t ttimer = millis ( ) ;
2021-11-21 21:21:37 +00:00
while ( client . connected ( ) & & ! client . available ( ) & & ( uint32_t ) ( millis ( ) - ttimer ) < maxWaitTime ) {
2020-12-02 12:07:04 +00:00
delay ( 10 ) ;
2020-11-26 17:40:39 +00:00
}
2021-11-21 21:21:37 +00:00
if ( ( ( uint32_t ) ( millis ( ) - ttimer ) > maxWaitTime ) & & serialDebug ) Serial . println ( " -Timed out " ) ;
2020-11-26 17:40:39 +00:00
2020-12-14 07:01:24 +00:00
// read the response
2021-11-21 21:21:37 +00:00
while ( client . connected ( ) & & client . available ( ) & & received_counter < maxChars ) {
delay ( 4 ) ;
2020-12-14 07:01:24 +00:00
received [ received_counter ] = char ( client . read ( ) ) ; // read one character
received_counter + = 1 ;
}
received [ received_counter ] = ' \0 ' ; // end of string marker
2021-11-21 21:21:37 +00:00
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
Serial . println ( " --------received web page----------- " ) ;
2020-12-14 07:01:24 +00:00
Serial . println ( received ) ;
2020-12-02 12:07:04 +00:00
Serial . println ( " ------------------------------------ " ) ;
2020-12-14 07:01:24 +00:00
Serial . flush ( ) ; // wait for serial data to finish sending
2020-12-02 12:07:04 +00:00
}
2021-11-21 21:21:37 +00:00
2020-12-02 12:07:04 +00:00
client . stop ( ) ; // close connection
if ( serialDebug ) Serial . println ( " Connection closed " ) ;
2020-12-14 07:01:24 +00:00
2021-11-21 21:21:37 +00:00
// if cuttoffText was supplied then only return the text following this
2020-12-14 07:01:24 +00:00
if ( cuttoffText ! = " " ) {
char * locus = strstr ( received , cuttoffText . c_str ( ) ) ; // locus = pointer to the found text
if ( locus ) { // if text was found
if ( serialDebug ) Serial . println ( " The text ' " + cuttoffText + " ' was found in reply " ) ;
return locus ; // return the reply text following 'cuttoffText'
} else if ( serialDebug ) Serial . println ( " The text ' " + cuttoffText + " ' WAS NOT found in reply " ) ;
}
2021-11-21 21:21:37 +00:00
2020-12-14 07:01:24 +00:00
return received ; // return the full reply text
2021-11-21 21:21:37 +00:00
} // requestWebPage
2020-11-26 17:40:39 +00:00
2020-12-02 12:07:04 +00:00
2020-11-14 16:20:58 +00:00
// ******************************************************************************************************************
// ----------------------------------------------------------------
// -test procedure i.e. http://x.x.x.x/test
// ----------------------------------------------------------------
void handleTest ( ) {
WiFiClient client = server . client ( ) ; // open link with client
// log page request including clients IP address
2020-12-02 12:07:04 +00:00
if ( serialDebug ) {
2020-11-14 16:20:58 +00:00
IPAddress cip = client . remoteIP ( ) ;
Serial . printf ( " Test requested from: %d.%d.%d.%d \n " , cip [ 0 ] , cip [ 1 ] , cip [ 2 ] , cip [ 3 ] ) ;
}
// html header
client . write ( " <!DOCTYPE html> <html lang='en'> <head> <title>photo</title> </head> <body> \n " ) ; // basic html header
// html body
2020-11-26 14:57:19 +00:00
client . print ( " <h1>Test Page</h1> \n " ) ;
2020-11-14 16:20:58 +00:00
2020-12-10 11:08:04 +00:00
// -------------------------------------------------------------------
2020-11-14 16:20:58 +00:00
2020-11-26 17:40:39 +00:00
2021-11-21 21:21:37 +00:00
// < YOUR TEST CODE GOES HERE>
2020-11-26 17:40:39 +00:00
2020-12-12 11:56:48 +00:00
2021-11-21 21:21:37 +00:00
// // demo useage of the mcp23017 io chip
2021-01-05 11:56:34 +00:00
// #if useMCP23017 == 1
// while(1) {
// mcp.digitalWrite(0, HIGH);
// int q = mcp.digitalRead(8);
// client.print("<p>HIGH, input =" + String(q) + "</p>");
// delay(1000);
// mcp.digitalWrite(0, LOW);
// client.print("<p>LOW</p>");
// delay(1000);
// }
// #endif
2020-12-12 11:56:48 +00:00
2020-12-10 11:08:04 +00:00
// -------------------------------------------------------------------
2021-11-21 21:21:37 +00:00
2020-11-14 16:20:58 +00:00
// end html
client . write ( " </body></html> \n " ) ;
delay ( 3 ) ;
client . stop ( ) ;
} // handleTest
2020-09-26 14:35:33 +00:00
// ******************************************************************************************************************
// end