8

I have a web server on an ESP32 and a homepage on that server. I would like to update sensor values on the homepage every x seconds automatically (without user input). I cannot access the file system.

The sensor is directly connected to the ESP32. The sensor values are in my C program, stored in variables and updated regularly. Variables are global for easier use.

I thought about Ajax (I have no experience), but all examples and methods I can find use a file to load data from (in the 'url'-part of XMLHttpRequest().open(...url....)). I have no file but only strings in which my HTML and Javascript code is generated and sent to the client.

I have no idea how to update my values and hope for some help.

I thought about trying something like the examples from w3schools, but I don't know how to get the values in there:

Example from another page (I don't use this code - I cannot use files!)

function loadDoc() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("demo").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "ajax_info.txt", true);
  xhttp.send();
}

Here is some code from my C program on the ESP:

HTML-String:

String html_document() {
  String sHTML;
  sHTML = "<!doctype html>";
  sHTML +="<html>";
  sHTML +="<html lang=\"de\">";
  /***************** head ****************/
  sHTML +="<head>";
  /****** avoid favicon requests **  ** <link rel=\"shortcut icon\" href=\"data:image/x-icon;,\" type=\"image/x-icon\"> **/
  sHTML +="<link rel=\"icon\" href=\"data:;base64,iVBORw0KGgo=\"> ";
  sHTML +="<meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">";
  //Anpassung an Viewport für unterschiedliche Devices
  /***************** title ***************/
  sHTML +="<title>LetsgoING IoT</title>";
  sHTML +="<style>h1{display: flex; flex-flow: row wrap; justify-content: center;} </style>";
  sHTML +="<style>h1{ color: green;}</style>";
  sHTML +="<style>h2{display: flex; flex-flow: row wrap; justify-content: center;} </style>";
  sHTML +="<style>h2{ color: blue;}</style>";
  sHTML +="<style>h5{display: flex; flex-flow: row wrap; justify-content: center;} </style>";
  sHTML +="<style>p{display: flex; flex-flow: row wrap; justify-content: center; margin-bottom: 3%;} </style>";
  sHTML +="<style>p1{display: flex; flex-flow: row wrap; justify-content: center; margin-bottom: 0%;} </style>";
  sHTML +="<style>p2{display: flex; flex-flow: row wrap; justify-content: center; margin-bottom: 0%;} </style>";
  sHTML +="</head>";
  /***************** body ****************/
  sHTML+= "<body>";   //onload=\"window.setInterval(updateDiv, 15000);\"
  sHTML+= "<h1>LetsgoING</h1>";
  sHTML+= "<h2>Internet der Dinge</h2>";
  sHTML+= "<p1><a style=\"width:38%;\"></a><a style=\"width:20%;color: green\">LED ein</a> <a style=\"width:15%;\" href=\"LEDON\"><button> EIN </button></a> </a><a style=\"width:27%;\"> </a></p1>";
  sHTML+= "<p><a style=\"width:38%;\"></a><a style=\"width:20%;color: red\"  >LED aus</a> <a style=\"width:15%\"; href=\"LEDOFF\"><button>AUS</button></a><a style=\"width:27%;\"> </a></p>";
  sHTML+= "<h5>RGB-LED PWM-Werte</h5>";
  sHTML+= "<form><p2>";
  sHTML+= "<a style=\"width:38%;\"></a> <a style=\"width:20%;color: red\"> Rot</a>  <a style=\"width:15%;\" ><input name=\"rot\" type=\"number\" min=\"0\" max=\"255\" step=\"1\" value=\"80\" ></a><a style=\"width:27%;\"> </a>";
  sHTML+= "<a style=\"width:38%;\"></a> <a style=\"width:20%;color: green\">Grün</a><a style=\"width:15%;\" ><input name=\"gruen\" type=\"number\" min=\"0\" max=\"255\" step=\"1\" value=\"80\"></a><a style=\"width:27%;\"> </a>";
  sHTML+= "<a style=\"width:38%;\"></a> <a style=\"width:20%;color: blue\">Blau</a> <a style=\"width:15%;\" ><input name=\"blau\" type=\"number\" min=\"0\" max=\"255\" step=\"1\" value=\"80\"></a><a style=\"width:27%;\"> </a>";
  sHTML+= "</p2>";
  sHTML+= "<p><a style=\"width:38%;\"></a> <a style=\"width:20%;\">         </a>   <label style=\"width:15%;\" ><input type=\"submit\" value=\"senden\"></label><a style=\"width:27%;\"></a></p>";
  sHTML+= "</form>";
  sHTML+= "<h5>analoger Schwellwert</h5>";
  sHTML+= "<form><p2><a style=\"width:38%;\"></a> <a style=\"width:20%;\"> <input name=\"schwell\" type=\"number\" min=\"0\" max=\"1024\" step=\"10\" value=\"300\"> </a> <a style=\"width:15%;\"><input type=\"submit\" value=\"senden\"></a><a style=\"width:27%;\"> </a></p2>";
  //sHTML+= "<p><a style=\"width:28%;\"></a> <a style=\"width:30%;\">         </a>   <label style=\"width:15%;\" ><input type=\"submit\" value=\"senden\"></label><a style=\"width:27%;\"></a></p>";
  sHTML+= "</form>";
  sHTML+= "<h5>PWM-Wert</h5>";
  sHTML+= "<form><p2><a style=\"width:38%;\"></a> <a style=\"width:20%;\"> <input name=\"pwm\" type=\"number\" min=\"0\" max=\"255\" step=\"1\" value=\"0\"> </a> <a style=\"width:15%;\"><input type=\"submit\" value=\"senden\"></a><a style=\"width:27%;\"> </a></p2>";
  sHTML+= "</form>";
  sHTML+= "<h5>Messwerte</h5>";
  sHTML+="<p><a style=\"width:38%;\"></a> <p3 id=\"an1\"; style=\"width:20%;\" href=\"anlg1\">#-Wert-#</p3><a style=\"width:22%;\">Analoger Pin 36   </a><a style=\"width:20%;\"></a></p>";
  sHTML+="<p><a style=\"width:38%;\"></a> <p3 id=\"an2\"; style=\"width:20%;\">#-Wert-#</p3><a style=\"width:22%;\">Analoger Pin 39   </a><a style=\"width:20%;\"></a></p>";
  sHTML+="<p><a style=\"width:38%;\"></a> <p3 id=\"dig\"; style=\"width:20%;\">#-Wert-#</p3><a style=\"width:22%;\">Digitaler Pin 5   </a><a style=\"width:20%;\"></a></p>";
  sHTML+= "</body>";
  sHTML+= "</html>";
  return sHTML;
}

Loop:

void loop() {
  if (millis() - startTime >= 2000) {
    startTime = millis();
    /* Check if a client has connected */
    client = server.available();
    if (!client){
      return;
    }
    /*Wait for the client to send data */
    Serial.println("neuer Client verbunden------------------------------");
    /*Count requests: */
    request_counter ++;
    unsigned long clTimeout = millis()+250;
    while(!client.available() && (millis()<clTimeout) ) {
      delay(1);
    }
    /***  publish Homepage ***/
    client.print(html_document());
    /* Read the first line of the clients request string "sHTML" until carriage return \r */
    sHTMLRequest = client.readStringUntil('\r');
    #ifdef DEBUGMODE
    Serial.println("Antwort: ");
    Serial.println(sHTMLRequest);
    #endif
    client.flush();
    /* stop client, if request is empty */
    if(sHTMLRequest=="") {
      Serial.println("Leere Anfrage! - client gestoppt");
      client.stop();
      return;
    }
    #ifdef DEBUGMODE
    Serial.println("Antwort2: ");
    Serial.println(sHTMLRequest);
    Serial.println ("---------");
    Serial.print("DEBUG: Remote IP - Address : ");
    for (int i = 0; i < 3; i++) {
      Serial.print( client.remoteIP()[i]);
      Serial.print(".");
    }
    Serial.println(client.remoteIP()[3]);
    Serial.print("Seitenaufrufe: ");
    Serial.println(request_counter);
    Serial.println ("---------");
    #endif
    /**** call event handler **********/
    eventHandler();
    #ifdef DEBUGMODE
    Serial.println("Zugewiesene PWM-Werte");
    Serial.print("rot: ");
    Serial.println(rot);
    Serial.print("gruen: ");
    Serial.println(gruen);
    Serial.print("blau: ");
    Serial.println(blau);
    #endif
    /* write PWM values for colors to channels*/
    ledcWrite(1, rot);
    ledcWrite(2, gruen);
    ledcWrite(3, blau);
    #ifdef DEBUGMODE
    Serial.println(analog1);
    #endif
  }
  UpdateValues();
}

/**** reads pin values **/
void UpdateValues() {
  analog1 = analogRead(pinAnalog1);
  analog2 = analogRead(pinAnalog2);
  DigiOut = digitalRead(LEDpin);
}

Here's the function that updates the values and creates the JSON string:

void UpdateValues() {
  analog1 = analogRead(pinAnalog1);
  analog2 = analogRead(pinAnalog2);
  DigiOut = digitalRead(LEDpin);
  String strJson;
  strJson = "(200,\"application/json\",\"{\"pin36\": ";
  strJson+=analog1;
  strJson+=", \"pin39\":";
  strJson+= analog2;
  strJson+=", \"pin5\": ";
  strJson+=DigiOut;
  strJson+="}\")";
  server.print(strJson);
}
7
  • So you have a sensor and you want to send its data to the esp32 webserver? What kind of sensor? Can you connect it directly to the esp32? Does the sensor have wireless capability? etc? Commented Jun 28, 2017 at 18:09
  • see edit above: sensordata is just any analog input value. No wireless sensor. the idea is to use esp's wifi. Commented Jun 28, 2017 at 18:27
  • You are making an ajax call to retrieve ajax_info.txt. Can you post the contents of that? Commented Jun 28, 2017 at 20:18
  • see edit: this is not any code I use, just an example from another page. i have no files and cannot use files. Commented Jun 28, 2017 at 20:19
  • I just cannot figure out how to get my values from the server to the hompage and updated regularly. I can only use a string in which i write the (html, javascript) code and I have no file with the values but variables in my c-program. I cannot create a file. Commented Jun 29, 2017 at 17:49

1 Answer 1

8
+200

Option 1:

The simplest way is to ask the page refresh itself every 5 seconds by adding this to <head>:

sHTML +="<meta http-equiv=\"refresh\" content=\"5\">";

Then change your sHTML string to concatenate the values of your global variables. Each time the page refreshes it will (should) rebuild the html and return the latest values.

Option 2:

You could use ajax to retrieve the latest values, and then frequently update the small section of the webpage that shows the data.

What happens here is you set up your ESP32 to provide a second URL, one that returns just the latest values as a json object. The values are then injected into the page, overwriting the old.

First add a link to jQuery in the <head>:

sHTML +="<script src=\"https://code.jquery.com/jquery-3.2.1.min.js\"></script>";

In the <body> add spans with ids to hold the values to be updated. Something like:

sHTML+= "<h5>Messwerte</h5>";
sHTML+="<p>Analoger Pin 36</p>&nbsp;<span id='pin36'></span>";
sHTML+="<p>Analoger Pin 39</p>&nbsp;<span id='pin39'></span>";
sHTML+="<p>Analoger Pin 5</p>&nbsp;<span id='pin5'></span>";

Create the sHTML for the following javascript that makes an ajax request every 5 seconds, and updates the latest values in the browser:

<script>
  $(function() {

    // request data every 5 seconds
    setInterval(requestData, 5000);

    function requestData() {

      // ajax request for latest sensor data
      $.get("/sensors")
        .done(function(data) {

          console.log(data);  // debugging - remove when satisfied

          if (data) { // if the returned data is not null, update the values
            $("#pin36").text(data.pin36);
            $("#pin39").text(data.pin39);
            $("#pin5").text(data.pin5);
          } else { // a problem occurred
            $("#pin36").text("?");
            $("#pin39").text("?");
            $("#pin5").text("?");
          }
        }).fail(function() {
          console.log("The was a problem retrieving the data.");
        });
    }

  });
</script>

When you detect the string /sensors in sHTMLRequest you want to return the following json format:

{"pin36": 5.2, "pin39": 0.322, "pin5": 1}

At this point I don't know enough about your setup to advise too much further, but these links should hopefully assist with the C code: http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html & http://randomnerdtutorials.com/esp32-web-server-arduino-ide/

If you use ESP32WebServer.h from https://github.com/nhatuan84/esp32-webserver (see second half of http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html for more details), you can use something like:

server.on("/sensors", handleSensorData);

with

/* this callback will be invoked when user request "/sensors" */
void handleSensorData() {
  /* server responds 200 with a json payload */
  /* although preferably concatenate your real sensor data here */
  server.send(200, "application/json", "{\"pin36\": 5.2, \"pin39\": 0.322, \"pin5\": 1}"); 
}
Sign up to request clarification or add additional context in comments.

9 Comments

This looks great I'll try this out as soon as I can!
Hello K Scandrett, is it possible that this code only works when connected to the internet? (ESP32 runs in AP mode and without internet connection) For that part: "....code.jquery.com/jquery-3.2.1.min.js ..." i get an error message in the browser: "Failed to load resource: net::ERR_NAME_NOT_RESOLVED -------- jquery-3.2.1.min.js "
Yes that will be the case, I did assume the computer you are connecting from has an internet connection. I can't respond properly right now, but will try to do so tomorrow
Here's the updated html & JavaScript that doesn't require an internet connection - plnkr.co/edit/7DyTmdRdWSIRxx7ESLNv?p=info. I'm not sure in your case if you need to use xhr.open('GET', 'sensors'); or xhr.open('GET', '/sensors');, so you may need to adjust accordingly
Note that server.send(20, "application/json", ...) only works if you're using ESP32WebServer.h. If you're not using it, then it will look more like s = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n ...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.