Serial monitor to web interface

Hello, newbie seeking for help here.

I'm working on a project that processes view from ESP-32 camera. Everything is going fine, I see the info that I need in serial monitor window. But is there any possibility to copy data that comes to serial monitor and transfer it via ESP32 Wi-Fi to web interface? I watched a lot of videos that shows how to create webserver but it reads pin value and send it to interface, but in my situation there's no pin value because it processes view from camera.

Any advise? Thank you very much.

void loop() {
    /* verify that there is no error in detecting the image from the camera */
    if (!capture_still()) {
        Serial.println("Failed capture");      
        return;
    }
// the following allows to count the number of people according to the direction of their movement 
   switch (motion_detect()){
    case 0 : 
      //Serial.println("no motion");
      list[1]=0;
      digitalWrite(12, LOW);
      digitalWrite(14, LOW);
      break;  
    case 1 : 
      //Serial.println("Iejo "); // when a person gets in that means that he is coming from the left side( the motion is detected from the left side of the photo) 
      list[1]= 1;
      digitalWrite(12, HIGH);
      digitalWrite(14, LOW);
      delay(100);
      break; 
    case -1 : 
      //Serial.println("Isejo"); // when a person gets out that means that he is coming from the right side( the motion is detected from the right side of the photo) 
      list[1]= -1 ;
      digitalWrite(12, LOW);
      digitalWrite(14, HIGH);
      delay(100);
      break;       
   }
   
 // if two directions or more are detected simultaneously (within milliseconds) only the first one will be selected     
    if ((list[0]==0) && (list[1]==1)){
       counter= counter+1 ; // if the person is getting in the building +1 is added 
    }else if ((list[0]==0) && (list[1]==-1)){
        counter=counter-1 ; //if the person is getting out the building 1 is substracted
       }
    list[0]= list[1]; //the current value will be the preview value

    if(counter>prevcounter) 
    {  
    Serial.println("ZMOGUS IEJO I PATALPA, PATALPOJE: ");
    Serial.print(counter) ; 
    Serial.println("=================");
    Serial.println("....................");}
    else if(counter<prevcounter)
    {  
    Serial.println("ZMOGUS ISEJO IS PATALPOS, PATALPOJE");
    Serial.print(counter) ; 
    Serial.println("=================");
    Serial.println("....................");}
    prevcounter=counter;
    update_frame();

If a client (web browser) sends a request to your webserver, you basically reply with something like

    client.print("ZMOGUS IEJO I PATALPA, PATALPOJE: ");
    client.print(counter) ; 
    client.print("=================");
    client.print("....................");}

Combine this with what you found on the web about a webserver that can send the status of pins and you should be good to go. Note that it needs a bit of polishing; e.g. there are no newlines as in your serial prints.

Your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advise on) your project :wink: See About the Installation & Troubleshooting category.

if you do a web serach for ESP32 web server you will get plenty of links with example code

To get the real-time data from ESP32, I would like to recommend you doing a search with "WebSocket"

So I tried using websocket ( ESP32 WebSocket Server: Control Outputs (Arduino IDE) | Random Nerd Tutorials ) and the page running fine. The problem is that I cant manage to find a way to send value to web interface because its not described. I dont know if I explained my problem correctly but seeking for help.

any help please :confused:

Sharing results of web interface.
Sharing code.

#define CAMERA_MODEL_AI_THINKER // define the type of the ESP camera 
// include the libraries 
#include "esp_camera.h"
#include "camera_pins.h"
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

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



// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
  }
  .topnav {
    overflow: hidden;
    background-color: #143642;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
  }
  .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    border: none;
    border-radius: 5px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
   }
   /*.button:hover {background-color: #0f8b8d}*/
   .button:active {
     background-color: #0f8b8d;
     box-shadow: 2 2px #CDCDCD;
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#8c8c8c;
     font-weight: bold;
   }
  </style>
<title>IEINANCIU IR ISEINANCIU ZMONIU APSKAITOS PRIETAISAS</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>IEINANCIU IR ISEINANCIU ZMONIU APSKAITOS PRIETAISAS</h1>
  </div>
  <div class="content">
    <div class="card">
      <h2>Zmoniu skaicius patalpoje</h2>
      <p class="state">state: <span id="state">%STATE%</span></p>
    </div>
  </div>
<script>
  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  window.addEventListener('load', onLoad);
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; // <-- add this line
  }
  function onOpen(event) {
    console.log('Connection opened');
  }
  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }
  function onLoad(event) {
    initWebSocket();
    initButton();
  }
  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }
</script>
</body>
</html>
)rawliteral";
#define FRAME_SIZE FRAMESIZE_QVGA // define the type of the frame size
#define WIDTH 320 //in pixels 
#define HEIGHT 240 //in pixels 
#define BLOCK_SIZE 10
#define W (WIDTH / BLOCK_SIZE) // in blocks 
#define H (HEIGHT / BLOCK_SIZE) //in blocks 
// define the scaling factor  which means the percent threshold above which we say that the block is actually changed
#define BLOCK_DIFF_THRESHOLD 0.2
//define the number of blocks above which an image is changed 
#define IMAGE_DIFF_THRESHOLD 0.2
#define DEBUG 1

/*initialize the variables needed in the program
*/
uint16_t prev_frame[H][W] = { 0 }; // the previous frame 
uint16_t current_frame[H][W] = { 0 };
int list[2]={0,0} ; // this list allows us to select only one direction when sereval directions are detected for just one person entering or getting out of the building 
int counter = -1 ,prevcounter=-1; 

/* define the used funtions 
 */
bool setup_camera(framesize_t);
bool capture_still();
int motion_detect();
void update_frame();
void print_frame(uint16_t frame[H][W]);
bool direction_detection ();
int freq(uint16_t frame[H][W],uint16_t a);
void notifyClients() {

}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    if (strcmp((char*)data, "toggle") == 0) {
    
      notifyClients();
    }
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
             void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

String processor(const String& var){
 {   if(counter>prevcounter) 
    {  
    Serial.println("ZMOGUS IEJO I PATALPA, PATALPOJE: ");
    Serial.print(counter) ; 
    Serial.println("=================");
    Serial.println("....................");}
    else if(counter<prevcounter)
    {  
    Serial.println("ZMOGUS ISEJO IS PATALPOS, PATALPOJE");
    Serial.print(counter) ; 
    Serial.println("=================");
    Serial.println("....................");}
    prevcounter=counter;
    update_frame();
      
}
  return String();
}


/**
 *
 */
void setup() {
    Serial.begin(115200);
    Serial.println(setup_camera(FRAME_SIZE) ? "OK" : "ERR INIT");
    pinMode(12, OUTPUT);  // initialize the GPIO12 pin as an output
    pinMode(14, OUTPUT);  // initialize the GPIO14 pin as an output

  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP Local IP Address
  Serial.println(WiFi.localIP());

  initWebSocket();

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Start server
  server.begin();
}


/**
 This is the main program where all the functions are called 
 */
 
void loop() {
    /* verify that there is no error in detecting the image from the camera */
    if (!capture_still()) {
        Serial.println("Failed capture"); 
         ws.cleanupClients();
    
        return;
    }
// the following allows to count the number of people according to the direction of their movement 
   switch (motion_detect()){
    case 0 : 
      //Serial.println("no motion");
      list[1]=0;
      digitalWrite(12, LOW);
      digitalWrite(14, LOW);
      break;  
    case 1 : 
      //Serial.println("Iejo "); // when a person gets in that means that he is coming from the left side( the motion is detected from the left side of the photo) 
      list[1]= 1;
      digitalWrite(12, HIGH);
      digitalWrite(14, LOW);
      delay(100);
      break; 
    case -1 : 
      //Serial.println("Isejo"); // when a person gets out that means that he is coming from the right side( the motion is detected from the right side of the photo) 
      list[1]= -1 ;
      digitalWrite(12, LOW);
      digitalWrite(14, HIGH);
      delay(100);
      break;       
   }
   
 // if two directions or more are detected simultaneously (within milliseconds) only the first one will be selected     
    if ((list[0]==0) && (list[1]==1)){
       counter= counter+1 ; // if the person is getting in the building +1 is added 
    }else if ((list[0]==0) && (list[1]==-1)){
        counter=counter-1 ; //if the person is getting out the building 1 is substracted
       }
    list[0]= list[1]; //the current value will be the preview value

    if(counter>prevcounter) 
    {  
    Serial.println("ZMOGUS IEJO I PATALPA, PATALPOJE: ");
    Serial.print(counter) ; 
    Serial.println("=================");
    Serial.println("....................");}
    else if(counter<prevcounter)
    {  
    Serial.println("ZMOGUS ISEJO IS PATALPOS, PATALPOJE");
    Serial.print(counter) ; 
    Serial.println("=================");
    Serial.println("....................");}
    prevcounter=counter;
    update_frame();
      
}


/**
 * Camera setup
 */
bool setup_camera(framesize_t frameSize) {
    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_GRAYSCALE;
    config.frame_size = frameSize;
    config.jpeg_quality = 12;
    config.fb_count = 1;

    bool ok = esp_camera_init(&config) == ESP_OK;

    sensor_t *sensor = esp_camera_sensor_get();
    sensor->set_framesize(sensor, frameSize);

    return ok;
}

/**
 * Capture image and do down-sampling, this means that the image is divided into blocks instead of pixels in order to reduce noise 
 * A block is a 10x10 pixels
 */
bool capture_still() {
    camera_fb_t *frame_buffer = esp_camera_fb_get();

    if (!frame_buffer)
        return false;

    // set all 0s in current frame
    for (int y = 0; y < H; y++)
        for (int x = 0; x < W; x++)
            current_frame[y][x] = 0;


    // down-sample image in blocks
    for (uint32_t i = 0; i < WIDTH * HEIGHT; i++) {
        const uint16_t x = i % WIDTH;
        const uint16_t y = floor(i / WIDTH);
        const uint8_t block_x = floor(x / BLOCK_SIZE);
        const uint8_t block_y = floor(y / BLOCK_SIZE);
        const uint8_t pixel = frame_buffer->buf[i];
        const uint16_t current = current_frame[block_y][block_x];

        // average pixels in block (accumulate)
        current_frame[block_y][block_x] += pixel;
    }

    // average pixels in block (rescale)
    for (int y = 0; y < H; y++)
        for (int x = 0; x < W; x++)
            current_frame[y][x] /= BLOCK_SIZE * BLOCK_SIZE;

#if DEBUG
    //Serial.println("Current frame:");
    //print_frame(current_frame);
    //Serial.println("Preview frame:");
    //print_frame(prev_frame);
    //Serial.println("---------------");
#endif

    return true;
}
/* this function is used to determin the direction of the movement by dividing the direction matrix 
 * calculated in motion_detect() function into one right side matrix and one left side matrix,
 * the matrix with the higher frequency in "99" shows the direction from which the movement is coming 
 */
bool direction_detection(uint16_t frame[H][W]){
  // initialize the two direction matrices 
  uint16_t direc_left[H][W] = { 0 };
  uint16_t direc_right[H][W] = { 0 };
  
  for (int y = 0; y < H ; y++) {
      for (int x = 0; x < W; x++){
        if(x < W/2 ) {                   
          direc_left[y][x] = frame[y][x];
          direc_right[y][x] = { 0 };
        } 
        else {
           direc_right[y][x] = frame[y][x];
           direc_left[y][x] = { 0 };
        }
      } 
      }
      //print_frame(direc_left);
      //Serial.println("---------------");
      //print_frame(direc_right);

      
      //Serial.println("....................");
  if (freq(direc_right,{99}) > freq(direc_left,{99})) {
    //Serial.println("Rechts Richtung");
    return false;
    } else if (freq(direc_right,{99}) < freq(direc_left,{99})) { 
      //Serial.println("Links Richtung");
      return true; 
    }
    //else {
      //Serial.println("error keine Richtung detektiert ");
    //} 
   
}


/**
 * Compute the number of different blocks
 * If there are enough, then motion happened
 */

int motion_detect(){
    uint16_t changes = {0}; //initialize the number of changed blocks 
    const uint16_t blocks = (WIDTH * HEIGHT) / (BLOCK_SIZE * BLOCK_SIZE); // set the number of blocks in the picture
    uint16_t direc[H][W] = { 0 };
    // set the direction matrix to all 0s
    for (int y = 0; y < H; y++)
       { for (int x = 0; x < W; x++)
       {direc[y][x] = {0};}}
    // compare the blocks of the current frame with the blocks of the previous frame and calculate the delta factor 
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            float current = current_frame[y][x]; 
            float prev = prev_frame[y][x];
            float delta = abs(current - prev) / prev;
    
            if (delta >= BLOCK_DIFF_THRESHOLD) { 
#if DEBUG
                  
                //Serial.print("diff\t");
                //Serial.print(y);
                //Serial.print('\t');
                //Serial.println(x);
                //delay(100);
                
                changes += 1;  //if the block has changed considerably then add one to the number of changed blocks 
                direc[y][x] = {99} ; // write 99 in the direction matrix refering to the changed block 
 #endif               
            }
    }
    }
     //Serial.print("Changed ");
     //Serial.print(changes);

     if ((1.0 * changes / blocks) > IMAGE_DIFF_THRESHOLD){
      if  (direction_detection(direc)) {
          return 1;  // 1 means there is motion from the leftside ==> someone is getting in
      } else {
        return -1 ; //-1 means there is motion from the rightside ==> someone is getting out  
      }  
    } else {
      return 0; // there is no motion 
    }
}




/**
 * Copy current frame to previous
 */
void update_frame() { 
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            prev_frame[y][x] = current_frame[y][x];
        }
    }
}
/**
 * calculate the frequency of a number in a HxW matrix 
 */
int freq(uint16_t matrix[H][W],uint16_t a) {
   int freq = 0 ; 
   for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            if (matrix[y][x] == a) {
              freq = freq +1 ;
            }
        }
    }
    return freq ;

}

/**
 * For serial debugging ürint the frame 
 */
void print_frame(uint16_t frame[H][W]) {
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            Serial.print(frame[y][x]);
            Serial.print('\t');
        }

        Serial.println();
    }
}

is this esp32-web-server-sent-events-sse similar to what you are attempting?

It is, but it has exact data to print in web because of sensor, mines turn out to be calculation

what type of calculation? wht is the result? text, numbers, ?
I don't have a BME280 so I calculate the temperature on each event, e.g.

void getSensorReadings(){
  static int x=1;
  temperature = 23+x++;// bme.readTemperature();

and in loop() it is sent

    events.send(String(temperature).c_str(),"temperature",millis());

the serial monitor displays

Connecting to WiFi .....192.168.1.164
Could not find a valid BME280 sensor, check wiring!
Temperature = 24.00 ºC 
Humidity = 0.00 
Pressure = 0.00 hPa 

Temperature = 25.00 ºC 
Humidity = 0.00 
Pressure = 0.00 hPa 

Temperature = 26.00 ºC 
Humidity = 0.00 
Pressure = 0.00 hPa 

so the temperature displayed on webclient URL 192.168.1.194 is 24, 25, 26, etc etc

So how can I read my serial monitor data because i'm not using BME sensors...

delete the BME280 code
in loop() replace getSensorReadings(); (which reads the BME280) with code to read your sensors

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    getSensorReadings();

update the HTML, eventlisteners, etc to to match your sensors

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.