├── Images ├── P_20200203_075402.jpg ├── P_20200203_075407.jpg ├── P_20200203_085529.jpg ├── ProjInOperation.jpg ├── Schematic_Modules_bb.png ├── Schematic_Sender_Module.fzz ├── Screenshot_03.PNG ├── Screenshot_20200203-085512.png └── Screenshot_20200203-090351.png ├── README.md ├── Script_01_Adjust_DS3231_Time └── Script_01_Adjust_DS3231_Time.ino ├── Script_02_ESP32_ESPNowSender ├── Script_02_ESP32_ESPNowSender.ino └── SenderModule_Constants_Structs.h └── Script_03_ESP32CAM_ESP-NOW_WebServer ├── Constants_structs_and_functions.h ├── Script_03_ESP32CAM_ESP-NOW_WebServer.ino └── WebServer_ESP32CAM.h /Images/P_20200203_075402.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/P_20200203_075402.jpg -------------------------------------------------------------------------------- /Images/P_20200203_075407.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/P_20200203_075407.jpg -------------------------------------------------------------------------------- /Images/P_20200203_085529.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/P_20200203_085529.jpg -------------------------------------------------------------------------------- /Images/ProjInOperation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/ProjInOperation.jpg -------------------------------------------------------------------------------- /Images/Schematic_Modules_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/Schematic_Modules_bb.png -------------------------------------------------------------------------------- /Images/Schematic_Sender_Module.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/Schematic_Sender_Module.fzz -------------------------------------------------------------------------------- /Images/Screenshot_03.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/Screenshot_03.PNG -------------------------------------------------------------------------------- /Images/Screenshot_20200203-085512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/Screenshot_20200203-085512.png -------------------------------------------------------------------------------- /Images/Screenshot_20200203-090351.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualvim/ESP32CAM_ESPNOW_Sensors_WebServer/9afd9f4138196d14fb9037d025ae23f64ea7ba78/Images/Screenshot_20200203-090351.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 and ESP32-CAM: Web Server and **ESP-NOW** protocol 2 | - This project is a modification of this project: https://github.com/dualvim/WebServer_ESP32CAM_Sensors_MQTT 3 | - In the former project, an ESP8266 board read some sensors and an ESP32-CAM board receved these data via MQTT protocol. 4 | - This project uses the **ESP-NOW protocol** to send data from one ESP32 board to another. 5 | - This project uses two boards with ESP32 SoC: 6 | - Module 1: NodeMCU with **ESP-WROOM-32**/**ESP-32S** 7 | - Module 2: **ESP32-CAM**, which includes an OV2640 camera module and a MicroSD card module. 8 | - The **NodeMCU ESP32** board is connected to some sensors - temperature, air pressure, humidity, light and Real Time Clock (RTC) - and it sends the values read in these sensors to an ESP32-CAM board. 9 | - The **ESP32-CAM** board hosts a web server which shows the last picture taken by the camera (saved in the SPIFFS) and the values received from the first board. 10 | - The Wi-Fi module in this board works on the **`WIFI_AP_STA`** mode which combines the modes **Station (`WIFI_STA`)** and **Soft Access Point (`WIFI_AP`)**. 11 | - It creates an Soft Access Point, where the other ESP boards connects to. 12 | - Also, it is connected to a Wi-Fi network with internet connection. 13 | - With this configuration, the web server hosted in the board can be accessed by two different manners: 14 | - 1 - Over a device (computer, cell phone etc.) connected on the same Wi-Fi network, by typing the IP address of the web server. 15 | - 2 - By redirecting the IP address of the web server to the internet. Here, I use the services from **NGROK**. 16 | 17 | 18 | # 1 - References: 19 | - This project was built over many ideas presented in many posts published by **Rui Santos** and **Sara Santos** in the **Random Nerd Tutorials** (https://randomnerdtutorials.com/) and in the book-course **"Learn ESP32 with Arduino IDE"**, written by the same authors. 20 | - Many parts of the code written for the ESP32-CAM board where taken from this post: https://randomnerdtutorials.com/esp32-cam-take-photo-save-microsd-card/ 21 | - The (excellent) posts about the ESP-NOW protocol are: 22 | - 1 - https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/ 23 | - 2 - https://randomnerdtutorials.com/esp-now-two-way-communication-esp32/ 24 | 25 | 26 | # 2 - The ESP-NOW protocol 27 | - The scripts here use the protocol ESP-NOW only with ESP32 boards. I tried these scripts with an ESP8266 but it didn't work. 28 | - The ESP-NOW protocol **ALSO works with the ESP8266, but with other resources** (which I don't know yet). 29 | - The ESP-NOW is used for data transference between two or more ESP boards, and, of course, is available only in Espressif (company which developed the ESP-NOW, the ESP8266 and the ESP32) devices. 30 | - This project uses a **One-Way Connection** between the two ESP32 boards. 31 | - The NodeMCU board reads the sensors and **SENDS** the data to the ESP32-CAM board. 32 | - The ESP32-CAM board **RECEIVES** the data from the NodeMCU and publish the received data in the web server. 33 | - The web server hosted in the ESP32-CAM is redirected to the internet using the services from NGROK (https://ngrok.com/). 34 | 35 | 36 | # 3 - Parts used in this project: 37 | - NodeMCU ESP32 board - x1 38 | - ESP32-CAM board - x1 39 | - ZS-042 RTC module (with the DS3231 RTC) - x1 40 | - DHT22 sensor (temperature and humidity) - x1 41 | - BMP280 sensor module (temperature and air pressure) - x1 42 | - BH1750FVI light sensor module - x1 43 | - Light Dependent Resistor (LDR) - x1 44 | - FTDI programmer **FT232RL** or **CP2101** based (to send the sketch to the ESP32-CAM and/or use as power supply) - x1 45 | - MicroSD card - x1 46 | 47 | 48 | # 4 - Sketches: 49 | 50 | 51 | # 4.1 - Sketches of the project: 52 | - **`Script_01_Adjust_DS3231_Time`**: Its only function is to adjust the date and time in the RTC module. 53 | - **`Script_02_ESP32_ESPNowSender`**: Sketch sent to the NodeMCU ESP32 (the **SENDER** in this project). 54 | - **`Script_03_ESP32CAM_ESP-NOW_WebServer`**: Sketch sent to the ESP32-CAM (the **RECEIVER** in this project). 55 | 56 | 57 | # 4.2 - Using the ESP-NOW and the Wi-Fi in the ESP32: 58 | - Changes in the **RECEIVER** sketch: 59 | - 1 - Set the Wi-Fi mode to **AP+STA mode** (Soft Access Point and STAtion). 60 | - 2 - Create a Soft Access Point. 61 | - 3 - Connect to your Wi-Fi network. 62 | 63 | ``` 64 | void setup(){ 65 | /* Code before the ESP-NOW initialization */ 66 | 67 | // Set the Wi-Fi mode to AP+STA 68 | WiFi.mode(WIFI_AP_STA); 69 | 70 | // Create the Soft Access Point 71 | Serial.print("Creating the soft-AP..."); 72 | WiFi.softAP(, , , 1); 73 | 74 | // Connect to the Wi-Fi Network 75 | WiFi.begin(, ); 76 | 77 | 78 | /* Initialize the ESP-NOW and subsequent code in setup() */ 79 | } 80 | ``` 81 | 82 | 83 | - Changes in the **SENDER** sketch: 84 | - 1 - Set the Wi-Fi mode to **STA mode** (Station). 85 | - 2 - Connect to the Soft AP of the RECEIVER module, using the same procedure to connect to any other Wi-Fi network. 86 | 87 | ``` 88 | void setup(){ 89 | /* Code before the ESP-NOW initialization */ 90 | 91 | // Set the Wi-Fi mode to STA 92 | WiFi.mode(WIFI_STA); 93 | 94 | // Connect to the Soft Access Point 95 | WiFi.begin(, ); 96 | 97 | 98 | /* Initialize the ESP-NOW and subsequent code in setup() */ 99 | } 100 | ``` 101 | 102 | 103 | # 5 - Images: 104 | - Link to access the Web Server on the internet: http://0.tcp.ngrok.io:11614/ 105 | - This address changes everytime the NGROK service is called. 106 | - This address is only valid for 2020-02-03. 107 | - Here is shown some important images of the project. More images are available in the folder **`Images`**. 108 | 109 | 110 | ## 5.1 - Schematic diagram (built using Fritzing) 111 | ![Schematics](./Images/Schematic_Modules_bb.png) 112 | 113 | - More information about Fritzing in: https://fritzing.org/home/ 114 | 115 | 116 | 117 | ## 5.2 - Project in operation: 118 | ![Operation](./Images/ProjInOperation.jpg) 119 | 120 | 121 | ## 5.3 - Screenshot 122 | ![Operation](./Images/Screenshot_20200203-090351.png) 123 | -------------------------------------------------------------------------------- /Script_01_Adjust_DS3231_Time/Script_01_Adjust_DS3231_Time.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Script_01_Adjust_DS3231_Time.ino 3 | * 4 | *--> Adjust the RTC module DS3231 time 5 | */ 6 | 7 | #include "RTClib.h" 8 | 9 | 10 | 11 | 12 | /************************* 13 | ** struct RTC_Data ** 14 | *************************/ 15 | struct rtc_data { 16 | uint8_t hh; 17 | uint8_t hm; 18 | uint8_t hs; 19 | uint16_t dy; 20 | uint8_t dm; 21 | uint8_t dd; 22 | float tmp; 23 | String str_date; 24 | String str_hour; 25 | 26 | }; 27 | 28 | // Type 'RTC_Data' 29 | typedef struct rtc_data RTC_Data; 30 | 31 | 32 | //--> Global variable of type 'RTC_Data' 33 | RTC_Data ds3231_data; 34 | 35 | 36 | // --> Object to control the DS3231 module 37 | RTC_DS3231 rtc; 38 | 39 | 40 | 41 | // --> Function prototypes 42 | void get_formatted_hour( RTC_Data *p_rtc_data ); 43 | void get_formatted_date( RTC_Data *p_rtc_data ); 44 | void update_fields_struct_rtc_data( RTC_Data *p_rtc_data ); 45 | 46 | 47 | 48 | /****************** 49 | ** setup() ** 50 | ******************/ 51 | void setup() { 52 | Serial.begin(115200); 53 | rtc.begin(); 54 | 55 | Serial.println(F(__DATE__)); 56 | Serial.println(F(__TIME__)); 57 | // Set the date and time in the RTC module 58 | //rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 59 | 60 | 61 | } 62 | 63 | 64 | 65 | /**************** 66 | ** loop() ** 67 | ****************/ 68 | void loop() { 69 | // Get the date and time in the RTC module 70 | update_fields_struct_rtc_data( &ds3231_data ); 71 | 72 | // Print the date, time and temperature 73 | Serial.print(ds3231_data.str_date); Serial.print(" - "); 74 | Serial.print(ds3231_data.str_hour); Serial.print(" - "); 75 | Serial.print(ds3231_data.tmp); Serial.println(" ºC"); 76 | delay(5000); 77 | 78 | } 79 | 80 | 81 | /************************* 82 | ** Auxiliary functions ** 83 | *************************/ 84 | void get_formatted_date( RTC_Data *p_rtc_data ){ 85 | String str_rtc_date = ""; 86 | 87 | str_rtc_date += String(p_rtc_data->dy) + "-"; 88 | 89 | if( p_rtc_data->dm < 10 ){ str_rtc_date += "0"; } 90 | str_rtc_date += String(p_rtc_data->dm) + "-"; 91 | 92 | if( p_rtc_data->dd < 10 ){ str_rtc_date += "0"; } 93 | str_rtc_date += String(p_rtc_data->dd); 94 | 95 | p_rtc_data->str_date = str_rtc_date; 96 | } 97 | 98 | 99 | void get_formatted_hour( RTC_Data *p_rtc_data ){ 100 | String str_rtc_hour = ""; 101 | 102 | if( p_rtc_data->hh < 10 ){ str_rtc_hour += "0"; } 103 | str_rtc_hour += String(p_rtc_data->hh) + ":"; 104 | 105 | if( p_rtc_data->hm < 10 ){ str_rtc_hour += "0"; } 106 | str_rtc_hour += String(p_rtc_data->hm) + ":"; 107 | 108 | if( p_rtc_data->hs < 10 ){ str_rtc_hour += "0"; } 109 | str_rtc_hour += String(p_rtc_data->hs); 110 | 111 | // Update the 'p_rtc_data->str_hour' field 112 | p_rtc_data->str_hour = str_rtc_hour; 113 | } 114 | 115 | 116 | void update_fields_struct_rtc_data( RTC_Data *p_rtc_data ){ 117 | DateTime time_now = rtc.now(); 118 | 119 | p_rtc_data->hh = (uint8_t) time_now.hour(); 120 | p_rtc_data->hm = (uint8_t) time_now.minute(); 121 | p_rtc_data->hs = (uint8_t) time_now.second(); 122 | p_rtc_data->dy = (uint16_t) time_now.year(); 123 | p_rtc_data->dm = (uint8_t) time_now.month(); 124 | p_rtc_data->dd = (uint8_t) time_now.day(); 125 | p_rtc_data->tmp = (float) rtc.getTemperature(); 126 | 127 | // Formatted strings: 128 | get_formatted_date( p_rtc_data ); 129 | get_formatted_hour( p_rtc_data ); 130 | } 131 | -------------------------------------------------------------------------------- /Script_02_ESP32_ESPNowSender/Script_02_ESP32_ESPNowSender.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Script_02_ESP32_ESPNowSender.ino 3 | * 4 | *--> Sketch which read the sensors and uses the ESP-NOW to send the data to the ESP32-CAM: 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include //I2C 11 | #include //Biblioteca para usar o BMP280 12 | #include "RTClib.h" 13 | #include 14 | #include "SenderModule_Constants_Structs.h" 15 | 16 | 17 | 18 | 19 | /***************************************** 20 | ** Constants and global-scope variables ** 21 | *****************************************/ 22 | #define LDR_PIN 27 //Pin connected to the LDR 23 | #define DHT_PIN 33 //Pin connected to the DHT22 module 24 | #define I2C_BMP280 0x76 //I2C address of the BMP280 module 25 | 26 | // Wi-Fi parameters 27 | #define CHAN_AP 2 // Wi-Fi Channel (1 to 13) 28 | 29 | // MAC address of the receiver module 30 | const uint8_t MAC_ESP32CAM[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 31 | 32 | // Struct used to send the data to the receiver 33 | Struct_RTC_Env_Data data_esp32_1; 34 | String status_msg = "ERROR"; 35 | 36 | // SSID and password of the Soft Access Point created in the ESP32-CAM 37 | const char* SSID_AP = "Soft-Access-Point"; 38 | const char* PASSWORD_AP = "123456789"; 39 | 40 | 41 | 42 | 43 | /***************************************************************** 44 | ** Objects to control the devices connected to the ESP32 board ** 45 | *****************************************************************/ 46 | RTC_DS3231 rtc; // Object to control the DS3231 module 47 | Adafruit_BMP280 bmp; //Object to control the BMP280 module 48 | BH1750FVI luximeter(BH1750FVI::k_DevModeContLowRes); // Object to control the BH1750FVI module 49 | DHT dht(DHT_PIN, DHT22);// Object to control the DHT22 module 50 | 51 | 52 | 53 | 54 | /************************* 55 | ** Function prototypes ** 56 | *************************/ 57 | void fcalback_data_sent( const uint8_t *mac_addr, esp_now_send_status_t deliv_status ); 58 | void connect_esp32_wifi_network( void ); 59 | void update_fields_struct_rtc_data( Struct_RTC_Env_Data *p_str_data ); 60 | void update_fields_bmp280_data( Struct_RTC_Env_Data *p_str_data ); 61 | void update_fields_dht22_data( Struct_RTC_Env_Data *p_str_data ); 62 | void update_fields_illuminationt_data( Struct_RTC_Env_Data *p_str_data ); 63 | 64 | 65 | 66 | 67 | /****************** 68 | ** setup() ** 69 | ******************/ 70 | void setup() { 71 | Serial.begin(115200); 72 | delay(3000); 73 | 74 | // Configure the pin connected to the LDR 75 | pinMode(LDR_PIN, INPUT); 76 | 77 | // Intialize the DS3231 module 78 | rtc.begin(); 79 | 80 | // Initialize the BMP280 module 81 | bmp.begin( I2C_BMP280 ); 82 | 83 | // Initialize the BH1750 module 84 | luximeter.begin(); 85 | 86 | // Initialize the DHT22 sensor: 87 | dht.begin(); 88 | 89 | 90 | /**************************************************************************************************** 91 | ** IMPORTANT: You must connect this module to the soft Access point where the web server is hosted ** 92 | ****************************************************************************************************/ 93 | WiFi.mode(WIFI_STA); // No problem in use the station mode in this module! 94 | connect_esp32_wifi_network(SSID_AP, PASSWORD_AP ); 95 | 96 | 97 | // --> Initialize the ESP-NOW: 98 | if( esp_now_init() != ESP_OK ){ 99 | Serial.println("Error initializing ESP-NOW"); 100 | return; 101 | } 102 | 103 | // --> Register the send callback function: 104 | esp_now_register_send_cb( fcalback_data_sent ); //Function called whenever the ESP32 sends data 105 | 106 | // Register new ESP-NOW peer: 107 | esp_now_peer_info_t peerInfo; 108 | memcpy(peerInfo.peer_addr, MAC_ESP32CAM, 6); 109 | peerInfo.channel = CHAN_AP; 110 | peerInfo.encrypt = false; 111 | 112 | // Add peer 113 | if (esp_now_add_peer(&peerInfo) != ESP_OK){ 114 | Serial.println("Failed to add peer"); 115 | return; 116 | } 117 | } 118 | 119 | 120 | 121 | 122 | 123 | 124 | /**************** 125 | ** loop() ** 126 | ****************/ 127 | void loop() { 128 | // Get the date and time in the RTC module 129 | update_fields_struct_rtc_data( &data_esp32_1 ); 130 | 131 | // Update the BMP280 data 132 | update_fields_bmp280_data( &data_esp32_1 ); 133 | 134 | // Update the DHT22 data 135 | update_fields_dht22_data( &data_esp32_1 ); 136 | 137 | // Update the illumination data 138 | update_fields_illuminationt_data( &data_esp32_1 ); 139 | 140 | // Send the data to the ESP32-CAM module 141 | esp_err_t result = esp_now_send(MAC_ESP32CAM, (uint8_t *) &data_esp32_1, sizeof(data_esp32_1)); 142 | 143 | 144 | if( result == ESP_OK ){ 145 | Serial.println("Delivery Success :)"); 146 | } 147 | else{ 148 | Serial.println("Delivery Fail :("); 149 | } 150 | 151 | // Wait 10s 152 | delay(10000); 153 | 154 | } 155 | 156 | 157 | 158 | 159 | /************************* 160 | ** Callback Function ** 161 | *************************/ 162 | // --> Callback function executed when a data is sent 163 | void fcalback_data_sent( const uint8_t *mac_addr, esp_now_send_status_t deliv_status ){ 164 | Serial.print("\r\nLast Packet Send Status:\t"); 165 | 166 | // Update the global variable 'status_msg' 167 | if( deliv_status == ESP_NOW_SEND_SUCCESS ){ 168 | Serial.println("Delivery Success"); 169 | status_msg = "OK"; 170 | 171 | } 172 | else { 173 | Serial.println("Delivery Fail"); 174 | status_msg = "ERROR"; 175 | } 176 | } 177 | 178 | 179 | 180 | 181 | /********************************************************************************* 182 | ** Function which connects the sender to the soft Acces Point in the ESP32-CAM ** 183 | *********************************************************************************/ 184 | void connect_esp32_wifi_network( const char* ssid, const char* password ) { 185 | // --> Connect the ESP32 to the Wi-Fi Network: 186 | Serial.println("------------------------------------------------------------"); 187 | // Connect to the Wi-Fi network 188 | WiFi.begin(ssid, password); 189 | Serial.print("Connecting to "); 190 | Serial.print(ssid); 191 | while (WiFi.status() != WL_CONNECTED) { 192 | Serial.print("."); 193 | delay(500); 194 | } 195 | Serial.println("Ok\nConected!"); 196 | 197 | // Show IP and MAC Address: 198 | Serial.print("IP Address: "); 199 | Serial.print(WiFi.localIP()); 200 | Serial.print("; MAC Address: "); 201 | Serial.println(WiFi.macAddress()); 202 | Serial.println("------------------------------------------------------------\n"); 203 | } 204 | 205 | 206 | 207 | 208 | /************************* 209 | ** Auxiliary functions ** 210 | *************************/ 211 | void update_fields_struct_rtc_data( Struct_RTC_Env_Data *p_str_data ){ 212 | DateTime time_now = rtc.now(); 213 | 214 | p_str_data->hh = (uint8_t) time_now.hour(); 215 | p_str_data->hm = (uint8_t) time_now.minute(); 216 | p_str_data->hs = (uint8_t) time_now.second(); 217 | p_str_data->dy = (uint16_t) time_now.year(); 218 | p_str_data->dm = (uint8_t) time_now.month(); 219 | p_str_data->dd = (uint8_t) time_now.day(); 220 | 221 | // temperature 222 | p_str_data->rtc_tmp = (float) rtc.getTemperature(); 223 | 224 | // Formated strings 225 | p_str_data->rtc_date = get_formatted_date( p_str_data ); 226 | p_str_data->rtc_hour = get_formatted_hour( p_str_data ); 227 | } 228 | 229 | 230 | void update_fields_bmp280_data( Struct_RTC_Env_Data *p_str_data ){ 231 | // Data from the BMP280 module 232 | p_str_data->bmp_temp = (float) bmp.readTemperature(); 233 | p_str_data->bmp_pres = (float) bmp.readPressure() / 100.0F; 234 | } 235 | 236 | 237 | void update_fields_dht22_data( Struct_RTC_Env_Data *p_str_data ){ 238 | p_str_data->dht_temp = dht.readTemperature(false); //Ler a temperatura 239 | p_str_data->dht_hum = dht.readHumidity(); 240 | } 241 | 242 | 243 | void update_fields_illuminationt_data( Struct_RTC_Env_Data *p_str_data ){ 244 | // Update field with the ADC value read in LDR pin 245 | p_str_data->adc_ldr = analogRead(LDR_PIN); 246 | delay(500); 247 | 248 | // Update field of the light intensity 249 | p_str_data->lux = luximeter.GetLightIntensity(); 250 | delay(500); 251 | } 252 | -------------------------------------------------------------------------------- /Script_02_ESP32_ESPNowSender/SenderModule_Constants_Structs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SenderModule_Constants_Structs.h 3 | * 4 | * --> This header file contains the structs and function prototypes of the functions commonly used in both ESP32 modules; 5 | * 6 | */ 7 | 8 | 9 | /******************************** 10 | ** struct Struct_RTC_Env_Data ** 11 | ********************************/ 12 | struct struct_rtc_env_data { 13 | uint16_t dy; 14 | uint8_t dm; 15 | uint8_t dd; 16 | uint8_t hh; 17 | uint8_t hm; 18 | uint8_t hs; 19 | float rtc_tmp; 20 | String rtc_date; 21 | String rtc_hour; 22 | float bmp_temp; 23 | float bmp_pres; 24 | float dht_temp; 25 | float dht_hum; 26 | uint16_t adc_ldr; 27 | uint16_t lux; 28 | }; 29 | 30 | 31 | // Type Struct_RTC_Env_Data 32 | typedef struct struct_rtc_env_data Struct_RTC_Env_Data; 33 | 34 | 35 | 36 | /************************* 37 | ** Function prototypes ** 38 | *************************/ 39 | String get_formatted_date( Struct_RTC_Env_Data *p_str_data ); 40 | String get_formatted_hour( Struct_RTC_Env_Data *p_str_data); 41 | double get_mean_temperature( Struct_RTC_Env_Data *p_str_data ); 42 | 43 | 44 | 45 | 46 | 47 | 48 | /************************* 49 | ** Auxiliary Functions ** 50 | *************************/ 51 | String get_formatted_date( Struct_RTC_Env_Data *p_str_data ){ 52 | String str_rtc_date = ""; 53 | 54 | str_rtc_date += String(p_str_data->dy) + "-"; 55 | 56 | if( p_str_data->dm < 10 ){ str_rtc_date += "0"; } 57 | str_rtc_date += String(p_str_data->dm) + "-"; 58 | 59 | if( p_str_data->dd < 10 ){ str_rtc_date += "0"; } 60 | str_rtc_date += String(p_str_data->dd); 61 | 62 | return str_rtc_date; 63 | } 64 | 65 | 66 | String get_formatted_hour( Struct_RTC_Env_Data *p_str_data){ 67 | String str_rtc_hour = ""; 68 | 69 | if( p_str_data->hh < 10 ){ str_rtc_hour += "0"; } 70 | str_rtc_hour += String(p_str_data->hh) + ":"; 71 | 72 | if( p_str_data->hm < 10 ){ str_rtc_hour += "0"; } 73 | str_rtc_hour += String(p_str_data->hm) + ":"; 74 | 75 | if( p_str_data->hs < 10 ){ str_rtc_hour += "0"; } 76 | str_rtc_hour += String(p_str_data->hs); 77 | 78 | // Update the 'p_str_data->str_hour' field 79 | return str_rtc_hour; 80 | } 81 | 82 | 83 | 84 | 85 | double get_mean_temperature( Struct_RTC_Env_Data *p_str_data ){ 86 | double mean_temp = p_str_data->rtc_tmp; 87 | mean_temp += (double) p_str_data->bmp_temp; 88 | mean_temp += (double) p_str_data->dht_temp; 89 | 90 | return mean_temp / (double)3.0; 91 | } 92 | -------------------------------------------------------------------------------- /Script_03_ESP32CAM_ESP-NOW_WebServer/Constants_structs_and_functions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Constants_structs_and_functions.h 3 | * 4 | * --> This header file contains the structs and functions used in both ESP32 modules; 5 | * 6 | */ 7 | 8 | 9 | /******************************** 10 | ** Simbolic constants ** 11 | ********************************/ 12 | // --> Pins from the OV2640 camera module (CAMERA_MODEL_AI_THINKER) 13 | #define PWDN_GPIO_NUM 32 14 | #define RESET_GPIO_NUM -1 // RESET pin is not available 15 | #define XCLK_GPIO_NUM 0 16 | #define SIOD_GPIO_NUM 26 //SDA pin - 'GPIO 26' 17 | #define SIOC_GPIO_NUM 27 //SCL pin - 'GPIO 26' 18 | #define Y9_GPIO_NUM 35 //D7 pin - 'GPIO 35' 19 | #define Y8_GPIO_NUM 34 //D6 pin - 'GPIO 34' 20 | #define Y7_GPIO_NUM 39 //D5 pin - 'GPIO 39' 21 | #define Y6_GPIO_NUM 36 //D4 pin - 'GPIO 36' 22 | #define Y5_GPIO_NUM 21 //D3 pin - 'GPIO 21' 23 | #define Y4_GPIO_NUM 19 //D2 pin - 'GPIO 19' 24 | #define Y3_GPIO_NUM 18 //D1 pin - 'GPIO 18' 25 | #define Y2_GPIO_NUM 5 //D0 pin - 'GPIO 5' 26 | #define VSYNC_GPIO_NUM 25 27 | #define HREF_GPIO_NUM 23 28 | #define PCLK_GPIO_NUM 22 29 | 30 | 31 | // --> EEPROM constants: picture number saved in card 32 | #define EEPROM_SIZE 1 33 | #define EEPROM_ADDRESS 0 34 | 35 | 36 | 37 | 38 | 39 | 40 | /******************************** 41 | ** struct Struct_RTC_Env_Data ** 42 | ********************************/ 43 | struct struct_rtc_env_data { 44 | uint16_t dy; 45 | uint8_t dm; 46 | uint8_t dd; 47 | uint8_t hh; 48 | uint8_t hm; 49 | uint8_t hs; 50 | float rtc_tmp; 51 | String rtc_date; 52 | String rtc_hour; 53 | float bmp_temp; 54 | float bmp_pres; 55 | float dht_temp; 56 | float dht_hum; 57 | uint16_t adc_ldr; 58 | uint16_t lux; 59 | }; 60 | 61 | 62 | // Type Struct_RTC_Env_Data 63 | typedef struct struct_rtc_env_data Struct_RTC_Env_Data; 64 | 65 | 66 | 67 | 68 | 69 | 70 | /************************* 71 | ** Function prototypes ** 72 | *************************/ 73 | String get_formatted_date( Struct_RTC_Env_Data *p_str_data ); 74 | String get_formatted_hour( Struct_RTC_Env_Data *p_str_data); 75 | double get_mean_temperature( Struct_RTC_Env_Data *p_str_data ); 76 | String get_file_name_sd_card( uint8_t pic_num ); 77 | 78 | 79 | 80 | 81 | 82 | 83 | /************************* 84 | ** Auxiliary Functions ** 85 | *************************/ 86 | String get_formatted_date( Struct_RTC_Env_Data *p_str_data ){ 87 | String str_rtc_date = ""; 88 | 89 | str_rtc_date += String(p_str_data->dy) + "-"; 90 | 91 | if( p_str_data->dm < 10 ){ str_rtc_date += "0"; } 92 | str_rtc_date += String(p_str_data->dm) + "-"; 93 | 94 | if( p_str_data->dd < 10 ){ str_rtc_date += "0"; } 95 | str_rtc_date += String(p_str_data->dd); 96 | 97 | return str_rtc_date; 98 | } 99 | 100 | 101 | String get_formatted_hour( Struct_RTC_Env_Data *p_str_data){ 102 | String str_rtc_hour = ""; 103 | 104 | if( p_str_data->hh < 10 ){ str_rtc_hour += "0"; } 105 | str_rtc_hour += String(p_str_data->hh) + ":"; 106 | 107 | if( p_str_data->hm < 10 ){ str_rtc_hour += "0"; } 108 | str_rtc_hour += String(p_str_data->hm) + ":"; 109 | 110 | if( p_str_data->hs < 10 ){ str_rtc_hour += "0"; } 111 | str_rtc_hour += String(p_str_data->hs); 112 | 113 | // Update the 'p_str_data->str_hour' field 114 | return str_rtc_hour; 115 | } 116 | 117 | 118 | double get_mean_temperature( Struct_RTC_Env_Data *p_str_data ){ 119 | double mean_temp = p_str_data->rtc_tmp; 120 | mean_temp += (double) p_str_data->bmp_temp; 121 | mean_temp += (double) p_str_data->dht_temp; 122 | 123 | return mean_temp / (double)3.0; 124 | } 125 | 126 | 127 | String get_file_name_sd_card( uint8_t pic_num ){ 128 | String path = (pic_num < 100) ? ((pic_num < 10) ? "/pic_00" : "/pic_0") : "/pic_"; 129 | path = path + String(pic_num) + ".jpg"; 130 | return path; 131 | } 132 | 133 | 134 | -------------------------------------------------------------------------------- /Script_03_ESP32CAM_ESP-NOW_WebServer/Script_03_ESP32CAM_ESP-NOW_WebServer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Script_03_ESP32CAM_ESP-NOW_WebServer.ino 3 | * 4 | * --> Sketch sent to the ESP32-CAM. 5 | * --> Activities: 6 | * - Receives the data from the ESP32 module 7 | * - Take a picture and saves it 8 | */ 9 | 10 | 11 | 12 | /************************* 13 | ** Include header files ** 14 | *************************/ 15 | #include "esp_camera.h" 16 | #include "esp_timer.h" 17 | #include "img_converters.h" 18 | #include "Arduino.h" 19 | #include "soc/soc.h" // Disable brownour problems 20 | #include "soc/rtc_cntl_reg.h" // Disable brownour problems 21 | #include "driver/rtc_io.h" 22 | #include 23 | #include "SD_MMC.h" // SD Card ESP32 24 | #include // SPIFFS of the ESP32-CAM 25 | #include // read and write from flash memory 26 | #include 27 | #include 28 | #include 29 | #include // --> Async web server 30 | #include 31 | #include "Constants_structs_and_functions.h" 32 | #include "WebServer_ESP32CAM.h" 33 | 34 | 35 | 36 | 37 | 38 | /***************************************** 39 | ** Global scope constants and variables ** 40 | *****************************************/ 41 | // Pin of the ESP32-CAM which is connected to the camera's flash 42 | #define FLASH_PIN 4 43 | 44 | // Soft AP constants 45 | const char* SSID_AP = "Soft-Access-Point"; 46 | const char* PASSWORD_AP = "123456789"; 47 | 48 | // Wi-Fi constants 49 | #define NETWORK_SSID "YOUR SSID" 50 | #define NETWORK_PASS "YOUR PASSWORD" 51 | #define CHAN_AP 2 // Wi-Fi Channel (1 to 13) 52 | 53 | // Camera constants 54 | #define FILE_PHOTO "/photo.jpg" 55 | 56 | // Time interval to take a new picture if no picture have been taken 57 | #define INTERVAL 10*60000 // 10 minutes 58 | 59 | 60 | // Global scope variables 61 | camera_config_t CONFIG_CAM; // OV2640 camera configuration 62 | Struct_RTC_Env_Data data_esp32_1; // Struct Struct_RTC_Env_Data 63 | unsigned long lastMillis = 0; // Milliseconds counter: 64 | double mean_temp; // Average temperature in the 3 sensors 65 | boolean takeNewPhoto = false; //Boolean indicating if it should take another photo 66 | 67 | 68 | 69 | 70 | // --> Object 'AsyncWebServer' 71 | AsyncWebServer server(8888); // Asynchronous web server in port 8888 72 | 73 | 74 | 75 | 76 | 77 | /****************************** 78 | ** Function prototypes ** 79 | ******************************/ 80 | // --> Callback functions 81 | void fcalback_data_received(const uint8_t * mac, const uint8_t *received_data, int len); 82 | void print_received_data( void ); 83 | String processor( const String& var ); 84 | // --> ESP32-CAM devices configuration 85 | void ov2640_camera_module_configurations( void ); 86 | void initialize_spiffs( void ); 87 | void init_microSD_card( void ); 88 | void connect_esp32_wifi_network( char* ssid, char* password ); 89 | // --> EEPROM data manipulation 90 | void set_value_in_eeprom_to_0( void ); 91 | uint8_t get_current_value_stored_in_eeprom( void ); 92 | void increment_current_value_stored_in_eeprom( void ); 93 | // --> Functions to take pictures 94 | bool check_photo( fs::FS &fs, String str_file ); 95 | void take_picture_save_spiffs( void ); 96 | String copy_picture_spiffs_sdmmc( void ); 97 | 98 | 99 | 100 | 101 | 102 | /****************** 103 | ** setup() ** 104 | ******************/ 105 | void setup() { 106 | // Serial ccnnection 107 | Serial.begin(115200); 108 | delay(3000); 109 | 110 | // Turn off the flash: 111 | pinMode(FLASH_PIN, OUTPUT); 112 | digitalWrite(FLASH_PIN, LOW); 113 | 114 | // Set the EEPROM value in 0 (just in the first time): 115 | set_value_in_eeprom_to_0(); 116 | 117 | // Initialize devices attached to the ESP32-CAM 118 | ov2640_camera_module_configurations(); //Intialize the OV2640 camera module 119 | initialize_spiffs(); // Initialize the SPIFFS 120 | init_microSD_card(); // Initialize the SD Card module 121 | 122 | 123 | 124 | 125 | /********************************************************************************** 126 | ** IMPORTANT: Create the Soft Access Point; 127 | ** --> The ESP32 module running the web server must be an access point 128 | ** --> The sender(s) module(s) must connect to this soft AP. 129 | ** --> The ESP32 board with the soft AP then connects to the Wi-Fi network 130 | **********************************************************************************/ 131 | // Connect to the Wi-Fi Network 132 | WiFi.mode(WIFI_AP_STA); 133 | Serial.print("Creating the soft-AP..."); 134 | WiFi.softAP(SSID_AP, PASSWORD_AP, CHAN_AP, 1); 135 | IPAddress IP = WiFi.softAPIP(); 136 | Serial.print("IP do AP "); 137 | Serial.print(SSID_AP); 138 | Serial.print(": "); 139 | Serial.println(IP); 140 | 141 | 142 | // --> Connect the ESP32-CAM to the Wi-Fi Network 143 | connect_esp32_wifi_network(NETWORK_SSID, NETWORK_PASS); 144 | 145 | // --> Initialize the ESP-NOW: 146 | if( esp_now_init() != ESP_OK ){ 147 | Serial.println("Error initializing ESP-NOW"); 148 | return; 149 | } 150 | 151 | // --> Regiter the receive callback function: 152 | esp_now_register_recv_cb(fcalback_data_received); //Function called whenever the ESP32 receives data 153 | 154 | 155 | 156 | 157 | // --> Configure the asynchronous web server 158 | // Route for root / web page 159 | server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/html", index_html); } ); 160 | 161 | // Date of the last data: 162 | server.on("/date_data", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", data_esp32_1.rtc_date.c_str()); }); 163 | 164 | // Hour of the last data: 165 | server.on("/hour_data", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", data_esp32_1.rtc_hour.c_str()); }); 166 | 167 | // Mean temperature: 168 | server.on("/temp_data", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", String(mean_temp).c_str()); }); 169 | 170 | // Air Pressuree: 171 | server.on("/press_data", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", String(data_esp32_1.bmp_pres).c_str()); }); 172 | 173 | // Humidity: 174 | server.on("/humid_data", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", String(data_esp32_1.dht_hum).c_str()); }); 175 | 176 | // ADC LDR: 177 | server.on("/ldr_data", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", String(data_esp32_1.adc_ldr).c_str()); }); 178 | 179 | // Lux: 180 | server.on("/lux_data", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", String(data_esp32_1.lux).c_str()); }); 181 | 182 | // Take a new picture 183 | server.on("/capture", HTTP_GET, [](AsyncWebServerRequest * request) { 184 | request->send_P(200, "text/plain", "Tirando uma foto...Aguarde!"); 185 | }); 186 | 187 | // Last picture taken 188 | server.on("/saved-photo", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(SPIFFS, FILE_PHOTO, "image/jpg"); }); 189 | 190 | 191 | // --> Start the asynchronous web server 192 | Serial.println("Starting the Web Server"); 193 | server.begin(); 194 | } 195 | 196 | 197 | 198 | /**************** 199 | ** loop() ** 200 | ****************/ 201 | void loop() { 202 | // --> If asked to take a new photo: 203 | if( takeNewPhoto ){ 204 | // Average temperature in the 3 sensors read: 205 | mean_temp = get_mean_temperature( &data_esp32_1 ); 206 | 207 | // Call the function to take a photo with the camera and save it on the SPIFFS 208 | take_picture_save_spiffs(); 209 | 210 | // Copy the picture saved in the SPIFFS to the SD card 211 | copy_picture_spiffs_sdmmc();//, &last_picture); 212 | 213 | // Update the value of 'takeNewPhoto' 214 | takeNewPhoto = false; 215 | } 216 | 217 | 218 | // --> Small delay to fix some issues with Wi-Fi stability 219 | delay(150); 220 | 221 | 222 | 223 | // --> If passed INTERVAL miliseconds without a new picture, change the value of 'takeNewPhoto' 224 | if( (millis() - lastMillis) > INTERVAL ){ 225 | lastMillis = millis(); 226 | takeNewPhoto = true; 227 | } 228 | 229 | } 230 | 231 | 232 | 233 | 234 | /************************* 235 | ** Callback Functions ** 236 | *************************/ 237 | // --> Callback function executed whern the module receives data 238 | void fcalback_data_received(const uint8_t * mac, const uint8_t *received_data, int len){ 239 | // Copy 'received_data' content to 'last_picture' 240 | memcpy(&data_esp32_1, received_data, sizeof(data_esp32_1)); 241 | // Number o received bytes: 242 | Serial.print("Bytes received: "); Serial.println(len); 243 | //Print the received data 244 | print_received_data(); 245 | } 246 | 247 | 248 | void print_received_data( void ){ 249 | // Print the date, time and temperature 250 | Serial.print(data_esp32_1.rtc_date); Serial.print(" - "); 251 | Serial.print(data_esp32_1.rtc_hour); Serial.print(" - "); 252 | Serial.print(data_esp32_1.rtc_tmp); Serial.println(" ºC"); 253 | 254 | // Print the other fields of the 'weather_data' module 255 | Serial.print("sizeof(data_esp32_1) = "); Serial.print(sizeof(data_esp32_1)); Serial.println(" bytes"); 256 | Serial.print("ADC LDR = "); Serial.print(data_esp32_1.adc_ldr); Serial.print("; "); Serial.print(data_esp32_1.lux); Serial.println(" lux"); 257 | Serial.print("Temp. BMP280 = "); Serial.print(data_esp32_1.bmp_temp); Serial.print(" ºC; Press. BMP280 = "); Serial.print(data_esp32_1.bmp_pres); Serial.println(" hPa"); 258 | Serial.print("Temp. DHT22 = "); Serial.print(data_esp32_1.dht_temp); Serial.print(" ºC; Humid. DHT22 = "); Serial.print(data_esp32_1.dht_hum); Serial.println("%"); 259 | Serial.print("Mean temperature = "); Serial.print(get_mean_temperature( &data_esp32_1 ) ); Serial.println(" ºC"); 260 | Serial.println("\n"); 261 | } 262 | 263 | 264 | // --> processor(): 265 | String processor( const String& var ) { 266 | //--> If 'var' is HOUR_DATA: 267 | if (var == "HOUR_DATA") { return data_esp32_1.rtc_hour; } 268 | 269 | //--> If 'var' is HOUR_PHOTO: 270 | else if (var == "HOUR_PHOTO") { return data_esp32_1.rtc_date; } 271 | 272 | 273 | //--> If 'var' is TEMP_DATA: 274 | else if (var == "TEMP_DATA") { return String(mean_temp); } 275 | 276 | //--> If 'var' is PRESS_DATA: 277 | else if (var == "PRESS_DATA") { return String(data_esp32_1.bmp_pres); } 278 | 279 | //--> If 'var' is HUMID_DATA: 280 | else if (var == "HUMID_DATA") { return String(data_esp32_1.dht_hum); } 281 | 282 | //--> If 'var' is LDR_DATA: 283 | else if (var == "LDR_DATA") { return String(data_esp32_1.adc_ldr); } 284 | 285 | //--> If 'var' is LUX_DATA: 286 | else if (var == "LUX_DATA") { return String(data_esp32_1.lux); } 287 | 288 | // --> Else, return empty string 289 | return String(); 290 | } 291 | 292 | 293 | 294 | 295 | /********************************************* 296 | ** Auxiliary Functions for the web server ** 297 | *********************************************/ 298 | void ov2640_camera_module_configurations( void ) { 299 | Serial.print("Inicializing the OV2640 camera module..."); 300 | // --> OV2640 camera configuration 301 | CONFIG_CAM.ledc_channel = LEDC_CHANNEL_0; 302 | CONFIG_CAM.ledc_timer = LEDC_TIMER_0; 303 | CONFIG_CAM.pin_d0 = Y2_GPIO_NUM; 304 | CONFIG_CAM.pin_d1 = Y3_GPIO_NUM; 305 | CONFIG_CAM.pin_d2 = Y4_GPIO_NUM; 306 | CONFIG_CAM.pin_d3 = Y5_GPIO_NUM; 307 | CONFIG_CAM.pin_d4 = Y6_GPIO_NUM; 308 | CONFIG_CAM.pin_d5 = Y7_GPIO_NUM; 309 | CONFIG_CAM.pin_d6 = Y8_GPIO_NUM; 310 | CONFIG_CAM.pin_d7 = Y9_GPIO_NUM; 311 | CONFIG_CAM.pin_xclk = XCLK_GPIO_NUM; 312 | CONFIG_CAM.pin_pclk = PCLK_GPIO_NUM; 313 | CONFIG_CAM.pin_vsync = VSYNC_GPIO_NUM; 314 | CONFIG_CAM.pin_href = HREF_GPIO_NUM; 315 | CONFIG_CAM.pin_sscb_sda = SIOD_GPIO_NUM; 316 | CONFIG_CAM.pin_sscb_scl = SIOC_GPIO_NUM; 317 | CONFIG_CAM.pin_pwdn = PWDN_GPIO_NUM; 318 | CONFIG_CAM.pin_reset = RESET_GPIO_NUM; 319 | CONFIG_CAM.xclk_freq_hz = 20000000; 320 | CONFIG_CAM.pixel_format = PIXFORMAT_JPEG; 321 | // --> Frame size: 322 | if (psramFound()) { 323 | CONFIG_CAM.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA 324 | CONFIG_CAM.jpeg_quality = 10; 325 | CONFIG_CAM.fb_count = 2; 326 | } 327 | else { 328 | CONFIG_CAM.frame_size = FRAMESIZE_SVGA; 329 | CONFIG_CAM.jpeg_quality = 12; 330 | CONFIG_CAM.fb_count = 1; 331 | } 332 | // --> Initialize the camera module 333 | esp_err_t err = esp_camera_init(&CONFIG_CAM); 334 | if (err != ESP_OK) { 335 | Serial.printf("Camera init failed with error 0x%x", err); 336 | return; 337 | } 338 | Serial.println("Ok!"); 339 | } 340 | 341 | 342 | 343 | /******************************************************** 344 | ** Connect the ESP32-CAM to the Wi-Fi Network ** 345 | ********************************************************/ 346 | void connect_esp32_wifi_network( char* ssid, char* password ) { 347 | // --> Connect the ESP32 to the Wi-Fi Network: 348 | Serial.println("------------------------------------------------------------"); 349 | // Connect to the Wi-Fi network 350 | WiFi.begin(ssid, password); 351 | Serial.print("Connecting to "); 352 | Serial.print(ssid); 353 | while (WiFi.status() != WL_CONNECTED) { 354 | Serial.print("."); 355 | delay(500); 356 | } 357 | Serial.println("Ok\nConected!"); 358 | // Show IP and MAC Address: 359 | Serial.print("IP Address: "); 360 | Serial.print(WiFi.localIP()); 361 | Serial.print("; MAC Address: "); 362 | Serial.println(WiFi.macAddress()); 363 | Serial.println("------------------------------------------------------------\n"); 364 | } 365 | 366 | 367 | 368 | 369 | 370 | /******************************************************** 371 | ** Initialize the ESP32-CAM SPIFFS and MicroSD module ** 372 | ********************************************************/ 373 | void initialize_spiffs( void ) { 374 | // Initialize the SPIFFS file system 375 | Serial.print("Starting the SPIFFS file system..."); 376 | if( !SPIFFS.begin( true ) ){ 377 | Serial.println("ERROR"); 378 | return; 379 | } 380 | else { delay(500); Serial.println("Ok!"); } 381 | } 382 | 383 | 384 | 385 | 386 | void init_microSD_card( void ){ 387 | Serial.println("Starting SD Card..."); 388 | if(!SD_MMC.begin()){ 389 | Serial.println("Error! --> SD Card Mount Failed"); 390 | return; 391 | } 392 | uint8_t cardType = SD_MMC.cardType(); 393 | if(cardType == CARD_NONE){ 394 | Serial.println("Error! --> No SD Card attached"); 395 | return; 396 | } 397 | Serial.print("Ok! --> cardType = "); 398 | Serial.println(cardType); 399 | } 400 | 401 | 402 | 403 | 404 | 405 | /************************************* 406 | ** Read/Update EEPROM value ** 407 | *************************************/ 408 | void set_value_in_eeprom_to_0( void ){ 409 | EEPROM.begin(EEPROM_SIZE); 410 | Serial.print("EEPROM Address: "); Serial.println(EEPROM.read( EEPROM_ADDRESS )); 411 | EEPROM.write(EEPROM_ADDRESS, 0); 412 | Serial.print("EEPROM = "); Serial.println(EEPROM.read(EEPROM_ADDRESS)); 413 | EEPROM.commit(); 414 | } 415 | 416 | 417 | uint8_t get_current_value_stored_in_eeprom( void ){ 418 | EEPROM.begin(EEPROM_SIZE); 419 | uint8_t curr = EEPROM.read(EEPROM_ADDRESS); 420 | return curr; 421 | } 422 | 423 | 424 | void increment_current_value_stored_in_eeprom( void ){ 425 | EEPROM.begin(EEPROM_SIZE); 426 | 427 | // Valor atual salvo na EEPROM 428 | uint8_t curr = EEPROM.read(EEPROM_ADDRESS ); 429 | 430 | // Incrementar o valor atual 431 | if( curr < 255 ){ ++curr; } 432 | else{ curr = 0;} 433 | 434 | // Salvar o valor atual na EEPROM 435 | EEPROM.write(EEPROM_ADDRESS, curr); 436 | EEPROM.commit(); 437 | } 438 | 439 | 440 | 441 | 442 | /************************************************** 443 | ** Functions using the camera and saving files ** 444 | **************************************************/ 445 | // --> Check if the picture file saved in SPIFFS is greater than 100 bytes 446 | bool check_photo( fs::FS &fs, String str_file ) { 447 | String path = str_file; 448 | File f_pic = fs.open( path.c_str() ); 449 | unsigned int pic_sz = f_pic.size(); 450 | f_pic.close(); 451 | return ( pic_sz > 100 ); 452 | } 453 | 454 | 455 | 456 | // --> Take a picture and save it in SPIFFS 457 | void take_picture_save_spiffs( void ){ 458 | // --> Turn on the flash 459 | digitalWrite(FLASH_PIN, HIGH); 460 | 461 | 462 | // Pointer to the photo data and booleans indicanting if the picture have been saved 463 | camera_fb_t * fb = NULL; // pointer 464 | bool ok = 0; // Boolean indicating if the picture file is correctly saved in the SPIFFS 465 | 466 | 467 | // --> Repeat the loop untill the files of the photo be correct 468 | do { 469 | // Take a picture with the camera 470 | Serial.print("Taking a picture with the OV2640 camera..."); 471 | fb = esp_camera_fb_get(); 472 | if (!fb) { 473 | Serial.println("ERROR! Camera capture failed"); 474 | return; 475 | } 476 | Serial.println("OK!"); 477 | 478 | // --> Save the picture in the SPIFFS 479 | Serial.println("Saving the photo in the SPIFFS"); 480 | File spiffs_file = SPIFFS.open(FILE_PHOTO, FILE_WRITE); 481 | if( !spiffs_file ) { 482 | Serial.println("Failed to open file in writing mode"); 483 | } 484 | else{ 485 | spiffs_file.write(fb->buf, fb->len); // payload (image), payload length 486 | Serial.print("The picture has been saved in the SPIFFS with the name "); 487 | Serial.print(FILE_PHOTO); 488 | Serial.print(" - Size: "); 489 | Serial.print(spiffs_file.size()); 490 | Serial.println(" bytes"); 491 | } 492 | spiffs_file.close(); // Close the file 493 | ok = check_photo( SPIFFS, FILE_PHOTO ); //Check if its ok 494 | 495 | esp_camera_fb_return(fb); 496 | } while ( !ok ); 497 | 498 | 499 | // --> Turn off the flash 500 | digitalWrite(FLASH_PIN, LOW); 501 | } 502 | 503 | 504 | 505 | // --> Copy to the SD card the picture saved in SPIFFS 506 | String copy_picture_spiffs_sdmmc( void ){//, Picture_Name *p_nome ){ 507 | // Get current value saved in EEPROM 508 | uint8_t pic_num = get_current_value_stored_in_eeprom(); 509 | 510 | // Filename in the SD card 511 | String filename_sd_card = get_file_name_sd_card( pic_num ); 512 | 513 | // Copy the filename to 'p_nome->pic_name' 514 | //p_nome->pic_name = filename_sd_card; 515 | 516 | // File handler from the image saved in SPIFFS 517 | File spiffs_file = SPIFFS.open( FILE_PHOTO ); 518 | 519 | // File with a copy of the SPIFFS image 520 | File mmc_file = SD_MMC.open( filename_sd_card.c_str(), FILE_WRITE); 521 | 522 | // Copy the content of 'spiffs_file' to 'mmc_file' 523 | static uint8_t buf[512]; 524 | while( spiffs_file.read(buf, 512) ){ 525 | mmc_file.write( buf, 512 ); 526 | } 527 | 528 | // Close the files 529 | spiffs_file.close(); 530 | mmc_file.close(); 531 | 532 | // Check and print the size of the file copyed to the MicroSD card 533 | File f_pic = SD_MMC.open( filename_sd_card.c_str() ); 534 | unsigned int pic_sz = f_pic.size(); 535 | f_pic.close(); 536 | Serial.print("Filename: "); Serial.print(filename_sd_card); 537 | Serial.print("\tSize: "); Serial.print(pic_sz); 538 | Serial.println(" bytes"); 539 | 540 | // Update the value saved in EEPROM 541 | increment_current_value_stored_in_eeprom(); 542 | 543 | // Return the string 'filename_sd_card' 544 | return filename_sd_card; 545 | } 546 | -------------------------------------------------------------------------------- /Script_03_ESP32CAM_ESP-NOW_WebServer/WebServer_ESP32CAM.h: -------------------------------------------------------------------------------- 1 | const char index_html[] PROGMEM = R"rawliteral( 2 | 3 | 4 | 5 | 11 | 12 | 13 |
14 |

SITUAÇÃO CLIMÁTICA ATUAL:

15 |

--> Local: Ribeirão Preto (região central) - SP - Brasil

16 |

-->Dados atualizados a cada 10s

17 |

Data: %DATE_DATA%

18 |

Hora: %HOUR_DATA%

19 |

Temperatura: %TEMP_DATA% ºC

20 |

Pressão: %PRESS_DATA% hPa

21 |

Umidade: %HUMID_DATA%%

22 | 23 |

Quantidade de lux: %LUX_DATA% lux

24 |
25 | 26 |

ÚLTIMA FOTO TIRADA COM O ESP32-CAM

27 |

--> Para tirar uma foto, clique no botão 'TIRAR FOTO'.

28 |

--> Geralmente o processo de tirar a foto e atualizar no site é maior que 10 segundos..

29 |

--> Depois de 15 a 20 segundos após tirar a foto, clicar no botão ATUALIZAR PÁGINA.

30 |

31 | 32 | 33 | 34 |

35 |
36 |
37 | 38 | 39 | 40 | 146 | )rawliteral"; 147 | --------------------------------------------------------------------------------