Web Server with ESP Boards

There is a website called Random Nerd Tutorials with many cool and well explained projects using Arduino based boards and Raspberry Pi.

I am going to share here two of these projects which I followed from their website.

The first one is using an ESP8266 Board to control two LEDs from your cell phone, laptop or any other device connected to your local network. You can also use this code to turn on/off any other device with your cell phone.

Here is a video:

You can follow the instructions on their website: Random Nerd Tutorials

/********* 
  Rui Santos 
  Complete project details at http://randomnerdtutorials.com   
*********/ 
 
// Load Wi-Fi library 
#include <ESP8266WiFi.h> 
 
// Replace with your network credentials 
const char* ssid     = "***************"; 
const char* password = "*******************"; 
 
// Set web server port number to 80 
WiFiServer server(80); 
 
// Variable to store the HTTP request 
String header; 
 
// Auxiliar variables to store the current output state 
String output5State = "off"; 
String output4State = "off"; 
 
// Assign output variables to GPIO pins 
const int output5 = 5; 
const int output4 = 4; 
 
void setup() {                            
  Serial.begin(115200); 
  // Initialize the output variables as outputs 
  pinMode(output5, OUTPUT); 
  pinMode(output4, OUTPUT); 
  // Set outputs to LOW 
  digitalWrite(output5, LOW); 
  digitalWrite(output4, LOW); 
 
  // Connect to Wi-Fi network with SSID and password 
  Serial.print("Connecting to "); 
  Serial.println(ssid); 
  WiFi.begin(ssid, password); 
  while (WiFi.status() != WL_CONNECTED) { 
    delay(500); 
    Serial.print("."); 
   } 
  // Print local IP address and start web server 
  Serial.println(""); 
  Serial.println("WiFi connected."); 
  Serial.println("IP address: "); 
  Serial.println(WiFi.localIP()); 
  server.begin(); 
} 
 
void loop(){ 
  WiFiClient client = server.available();   // Listen for incoming clients 
 
  if (client) {                    // If a new client connects, 
    Serial.println("New Client."); // print a message out in the serial port 
    String currentLine = "";       // make a String to hold incoming data  
    while (client.connected()) {   // loop while the client's connected 
      if (client.available()) {    // if there's bytes to read  
        char c = client.read();    // read a byte, then 
        Serial.write(c);           // print it out the serial monitor 
        header += c; 
        if (c == '\n') {               // if the byte is a newline character 
   // if the current line is blank, you got two newline characters in a row. 
   // that's the end of the client HTTP request, so send a response: 
          if (currentLine.length() == 0) { 
   // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)                            
   // and content-type so the client knows what's coming, then a blank line: 
            client.println("HTTP/1.1 200 OK"); 
            client.println("Content-type:text/html"); 
            client.println("Connection: close"); 
            client.println(); 
             
            // turns the GPIOs on and off 
            if (header.indexOf("GET /5/on") >= 0) { 
              Serial.println("GPIO 5 on"); 
              output5State = "on"; 
              digitalWrite(output5, HIGH); 
            } 
            else if (header.indexOf("GET /5/off") >= 0) { 
              Serial.println("GPIO 5 off"); 
              output5State = "off"; 
              digitalWrite(output5, LOW); 
            } 
            else if (header.indexOf("GET /4/on") >= 0) { 
              Serial.println("GPIO 4 on"); 
              output4State = "on"; 
              digitalWrite(output4, HIGH); 
            } 
            else if (header.indexOf("GET /4/off") >= 0) { 
              Serial.println("GPIO 4 off"); 
              output4State = "off"; 
              digitalWrite(output4, LOW); 
            } 
             
            // Display the HTML web page 
            client.println("<!DOCTYPE html><html>"); 
            client.println("<head><meta name=\"viewport\"content=\"width=device-width, initial-scale=1\">"); 
            client.println("<link rel=\"icon\" href=\"data:,\">"); 
            // CSS to style the on/off buttons  
            // Feel free to change the background-color and font-size attributes 
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}"); 
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;"); 
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}"); 
            client.println(".button2 {background-color: #77878A;}</style></head>");                            
             
            // Web Page Heading 
            client.println("<body><h1>ESP8266 Web Server</h1>"); 
             
            // Display current state, and ON/OFF buttons for GPIO 5   
            client.println("<p>GPIO 5 - State " + output5State + "</p>"); 
            // If the output5State is off, it displays the ON button        
            if (output5State=="off") { 
              client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>"); 
            } 
            else { 
              client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>"); 
            } 
              
            // Display current state, and ON/OFF buttons for GPIO 4   
            client.println("<p>GPIO 4 - State " + output4State + "</p>"); 
            // If the output4State is off, it displays the ON button        
            if (output4State=="off") { 
              client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>"); 
            } 
            else { 
              client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>"); 
            } 
            client.println("</body></html>"); 
             
            // The HTTP response ends with another blank line 
            client.println(); 
            // Break out of the while loop 
            break; 
          } else { // if you got a newline, then clear currentLine 
            currentLine = ""; 
          } 
        } 
        else if (c != '\r') {  // if you got anything else but a carriage return character
          currentLine += c;      // add it to the end of the currentLine 
        } 
      } 
    }     // Clear the header variable 
    header = ""; 
    // Close the connection 
    client.stop(); 
    Serial.println("Client disconnected."); 
    Serial.println(""); 
  } 
} 

The second project is using an ESP32-CAM board with OV2640 Camera Module. You can access from your cell phone, laptop or any other device connected to your local network the video streaming sent from the ESP32-CAM board and for example watch your pets from another room.

Here is a video:

You can follow the instructions on their website:

Random Nerd Tutorials

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com
  
  IMPORTANT!!! 
   - Select Board "ESP32 Wrover Module"
   - Select the Partion Scheme "Huge APP (3MB No OTA)
   - GPIO 0 must be connected to GND to upload a sketch
   - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h"  //disable brownout problems
#include "dl_lib.h"
#include "esp_http_server.h"

//Replace with your network credentials
const char* ssid = "*********";
const char* password = "*****************";

#define PART_BOUNDARY "123456789000000000000987654321"

// This project was only tested with the AI Thinker Model
#define CAMERA_MODEL_AI_THINKER

// Not tested with these boards
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_WROVER_KIT

#if defined(CAMERA_MODEL_WROVER_KIT)
  #define PWDN_GPIO_NUM    -1
  #define RESET_GPIO_NUM   -1
  #define XCLK_GPIO_NUM    21
  #define SIOD_GPIO_NUM    26
  #define SIOC_GPIO_NUM    27  
  #define Y9_GPIO_NUM      35
  #define Y8_GPIO_NUM      34
  #define Y7_GPIO_NUM      39
  #define Y6_GPIO_NUM      36
  #define Y5_GPIO_NUM      19
  #define Y4_GPIO_NUM      18
  #define Y3_GPIO_NUM       5
  #define Y2_GPIO_NUM       4
  #define VSYNC_GPIO_NUM   25
  #define HREF_GPIO_NUM    23
  #define PCLK_GPIO_NUM    22

#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
  #define PWDN_GPIO_NUM     -1
  #define RESET_GPIO_NUM    15
  #define XCLK_GPIO_NUM     27
  #define SIOD_GPIO_NUM     25
  #define SIOC_GPIO_NUM     23 
  #define Y9_GPIO_NUM       19
  #define Y8_GPIO_NUM       36
  #define Y7_GPIO_NUM       18
  #define Y6_GPIO_NUM       39
  #define Y5_GPIO_NUM        5
  #define Y4_GPIO_NUM       34
  #define Y3_GPIO_NUM       35
  #define Y2_GPIO_NUM       32
  #define VSYNC_GPIO_NUM    22
  #define HREF_GPIO_NUM     26
  #define PCLK_GPIO_NUM     21

#elif defined(CAMERA_MODEL_AI_THINKER)
  #define PWDN_GPIO_NUM     32
  #define RESET_GPIO_NUM    -1
  #define XCLK_GPIO_NUM      0
  #define SIOD_GPIO_NUM     26
  #define SIOC_GPIO_NUM     27
  #define Y9_GPIO_NUM       35
  #define Y8_GPIO_NUM       34
  #define Y7_GPIO_NUM       39
  #define Y6_GPIO_NUM       36
  #define Y5_GPIO_NUM       21
  #define Y4_GPIO_NUM       19
  #define Y3_GPIO_NUM       18
  #define Y2_GPIO_NUM        5
  #define VSYNC_GPIO_NUM    25
  #define HREF_GPIO_NUM     23
  #define PCLK_GPIO_NUM     22
#else
  #error "Camera model not selected"
#endif

static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

httpd_handle_t stream_httpd = NULL;

static esp_err_t stream_handler(httpd_req_t *req){
  camera_fb_t * fb = NULL;
  esp_err_t res = ESP_OK;
  size_t _jpg_buf_len = 0;
  uint8_t * _jpg_buf = NULL;
  char * part_buf[64];

  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  if(res != ESP_OK){
    return res;
  }

  while(true){
    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      res = ESP_FAIL;
    } else {
      if(fb->width > 400){
        if(fb->format != PIXFORMAT_JPEG){
          bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
          esp_camera_fb_return(fb);
          fb = NULL;
          if(!jpeg_converted){
            Serial.println("JPEG compression failed");
            res = ESP_FAIL;
          }
        } else {
          _jpg_buf_len = fb->len;
          _jpg_buf = fb->buf;
        }
      }
    }
    if(res == ESP_OK){
      size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
      res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
    }
    if(res == ESP_OK){
      res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
    }
    if(res == ESP_OK){
      res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    }
    if(fb){
      esp_camera_fb_return(fb);
      fb = NULL;
      _jpg_buf = NULL;
    } else if(_jpg_buf){
      free(_jpg_buf);
      _jpg_buf = NULL;
    }
    if(res != ESP_OK){
      break;
    }
    //Serial.printf("MJPG: %uB\n",(uint32_t)(_jpg_buf_len));
  }
  return res;
}

void startCameraServer(){
  httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  config.server_port = 80;

  httpd_uri_t index_uri = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = stream_handler,
    .user_ctx  = NULL
  };
  
  //Serial.printf("Starting web server on port: '%d'\n", config.server_port);
  if (httpd_start(&stream_httpd, &config) == ESP_OK) {
    httpd_register_uri_handler(stream_httpd, &index_uri);
  }
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);
  Serial.setDebugOutput(false);
  
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG; 
  config.frame_size = FRAMESIZE_UXGA;
  config.jpeg_quality = 10;
  config.fb_count = 2;
  
  // Camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
  // Wi-Fi connection
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  // Start streaming web server
  startCameraServer();
  Serial.print("Camera Stream Ready! Go to: http://");
  Serial.print(WiFi.localIP());
}

void loop() {
  delay(1);
}

Hinterlasse einen Kommentar

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..