[EN] ESP8266 WebServer

This article is an experiment to make the esp8266 microcontroller a web server to display temperature and humidity values from a DHT11 sensor using the Adafruit library as shown in Figure 1. When the microcontroller is run in SoftAP mode, the client or user connects to WiFi after using the browser to access 192.168.4.1 which is the IP of esp8266.

(Figure. 1 Our equipment)

Equipment

From Figure 1, it can be seen that we use the following equipment list.

  1. NodeMCU
  2. NodeMCU Base
  3. DHT11 Module

Connection

(Figure. 1 Our equipment)(Figure. 2 Circuit connection)

From the circuit in Figure 2, we choose Pin GPIO05 or D1 of esp8266 and use DHT11 that has R connected in the body as shown in Figure 4, so connect the pin as shown in Figures 3 and 4.

  • The yellow line is connected to 3V3 and +.
  • The brown line is connected to GND and -.
  • The orange line is connected to D1 or GPIO05 and s.
(Figure. 3 Connection on the esp8266 side )
(Figure. 4 Connection on the DHT11 side)

Test the program to make sure it works properly with the following code. The result is shown in Figure 5.

#include <DHT.h>

DHT dht = DHT(5, DHT11); // D1
float minC = 100.0f, maxC = 0.0f; // max, min degree
float minH = 100.0f, maxH = 0.0f; // max, min humidity
void setup() {
  Serial.begin(115200);
  Serial.println("\n\n\n");
  dht.begin();
}

void loop() {
  float h = dht.readHumidity();
  float tc = dht.readTemperature();
  float tf = dht.readTemperature(true);

  if (isnan(h) || isnan(tc) || isnan(tf)) {
    Serial.println("DHT11 connect failed!");
    return;
  }

  float hic = dht.computeHeatIndex(tc, h, false);
  float hif = dht.computeHeatIndex(tf, h);

  if (minC > tc) {
    minC = tc;
  }
  if (maxC < tc) {
    maxC = tc;
  }
  if (minH > h) {
    minH = h;
  }
  if (maxH < h) {
    maxH = h;
  }

  Serial.printf("Temperature: %.2fC/%.2fF Huminitt: %.2f%%, Heat index: %.2fC/%.2fF\n",
                tc, tf, h, hic, hif);
  Serial.printf("Temp. (%.2fC-%.2fC) Hum. (%.2f%%-%.2f%%)\n",
                minC, maxC, minH, maxH);
  delay(10000);
}
(Figure. 5 Result when read data from dht11)

Example Code

From the example of testing the operation of the circuit connected to the sensor DHT11 to become a Server, we can see that we have created external variables for storing various values as follows.

float minC = 100.0f, maxC = 0.0f; // max, min degree
float minH = 100.0f, maxH = 0.0f; // max, min humidity
float hic; // headt index ในหน่วย C
float hif;// headt index ในหน่วย F
float h; // humidity
float tc; // celcius degree
float tf; // fahrenheit degree

In addition, the readings section has been separated into a readout function named getDHT11() as follows, which checks if the sensor fails with a value of -1.0 without calculating the min/max of temperature and humidity again.

void getDHT11() {
  h = dht.readHumidity();
  tc = dht.readTemperature();
  tf = dht.readTemperature(true);

  if (isnan(h) || isnan(tc) || isnan(tf)) {
    h = -1.0f;
    tc = -1.0f;
    tf = -1.0f;
    hic = -1.0f;
    hif = -1.0f;
    return;
  }

  hic = dht.computeHeatIndex(tc, h, false);
  hif = dht.computeHeatIndex(tf, h);

  if (minC > tc) {
    minC = tc;
  }
  if (maxC < tc) {
    maxC = tc;
  }
  if (minH > h) {
    minH = h;
  }
  if (maxH < h) {
    maxH = h;
  }
}

The working principle of HTTP is to send the first request in the following format to port 80 (in the case of HTTP).

GET request HTTP/1.1

For example, GET / HTTP/1.1 means requesting a home page. So we wrote a function to respond to the homepage called getDHT11() to read the current temperature and humidity values ​​and calculate the Heat Index and the min/max values ​​of the temperature in degrees Celsius and relative humidity. After that, it responds to the requesting client by sending HTTP/1.1 200 OK code as the first data set, 200 is the response code indicating that the client request was successful. Other response codes are:

  • 200 The request was successful and replied back the information.
  • 404 The requested resource could not be found.
  • 302 The request has been relocated.
  • 500 The service provider is not available on request.
String htmlPage() {
  String html;
  getDHT11();
  html.reserve(2048);               // prevent ram fragmentation
  html = F("HTTP/1.1 200 OK\r\n"
           "Content-Type: text/html\r\n"
           "Connection: close\r\n"  // the connection will be closed after completion of the response
           "Refresh: 5\r\n"         // refresh the page automatically every 5 sec
           "\r\n"
           "<!DOCTYPE HTML>"
           "<html><head></head><body>"
           "<h1>DHT11</h1>");
  html += F("<div>Temperature:");
  html += tc;
  html += F("C/");
  html += tf;
  html += F("F</div>");
  html += F("<div>Huminity:");
  html += h;
  html += F("%</div>");
  html += F("<div>Temperature:");
  html += minC;
  html += F("C-");
  html += maxC;
  html += F("C</div>");
  html += F("<div>Huminity:");
  html += minH;
  html += F("%-");
  html += maxH;
  html += F("%</div>");
  html += F("</body></html>\r\n");
  return html;
}

So when all this is combined with the example of WiFiServer and the response as a web page reporting the values obtained from the sensor, it can be written as follows:

#include <DHT.h>
#include <ESP8266WiFi.h>

#define AP_NAME "JarutEx"
#define AP_PASSWD "123456789"
IPAddress myIP(192, 168, 4, 1);
IPAddress gwIP(192, 168, 4, 10);
IPAddress subnet(255, 255, 255, 0);

DHT dht = DHT(5, DHT11); // D1
WiFiServer server(80);

float minC = 100.0f, maxC = 0.0f; // max, min degree
float minH = 100.0f, maxH = 0.0f; // max, min humidity
float hic; // headt index  C
float hif;// headt index  F
float h; // humidity
float tc; //  Celcius degree
float tf; //  Fahrenheit

void getDHT11() {
  h = dht.readHumidity();
  tc = dht.readTemperature();
  tf = dht.readTemperature(true);

  if (isnan(h) || isnan(tc) || isnan(tf)) {
    h = -1.0f;
    tc = -1.0f;
    tf = -1.0f;
    hic = -1.0f;
    hif = -1.0f;
    return;
  }

  hic = dht.computeHeatIndex(tc, h, false);
  hif = dht.computeHeatIndex(tf, h);

  if (minC > tc) {
    minC = tc;
  }
  if (maxC < tc) {
    maxC = tc;
  }
  if (minH > h) {
    minH = h;
  }
  if (maxH < h) {
    maxH = h;
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n\n\n");
  dht.begin();
  if (WiFi.softAPConfig( myIP, gwIP, subnet )) {
    if (WiFi.softAP(AP_NAME, AP_PASSWD, 8, false, 5)) {
      Serial.print("IP Address : ");
      Serial.println(WiFi.softAPIP());
    } else {
      Serial.println("softAP() failed!!");
      while (true);
    }
  } else {
    Serial.println("softAPConfig() failed!");
    while (true);
  }
  server.begin();
}

String htmlPage() {
  String html;
  getDHT11();
  html.reserve(2048);               // prevent ram fragmentation
  html = F("HTTP/1.1 200 OK\r\n"
           "Content-Type: text/html\r\n"
           "Connection: close\r\n"  // the connection will be closed after completion of the response
           "Refresh: 5\r\n"         // refresh the page automatically every 5 sec
           "\r\n"
           "<!DOCTYPE HTML>"
           "<html><head></head><body>"
           "<h1>DHT11</h1>");
  html += F("<div>Temperature:");
  html += tc;
  html += F("C/");
  html += tf;
  html += F("F</div>");
  html += F("<div>Huminity:");
  html += h;
  html += F("%</div>");
  html += F("<div>Temperature:");
  html += minC;
  html += F("C-");
  html += maxC;
  html += F("C</div>");
  html += F("<div>Huminity:");
  html += minH;
  html += F("%-");
  html += maxH;
  html += F("%</div>");
  html += F("</body></html>\r\n");
  return html;
}

void loop() {
  WiFiClient client = server.available();

  if (client)   {
    Serial.println("\n[Client connected]");
    while (client.connected()) {
      if (client.available()) {
        String req = client.readStringUntil('\r');
        Serial.print(req);
        if (req.indexOf("GET / HTTP/1.1")) {
          client.println(htmlPage());
          break;
        }
      }
    }

    while (client.available()) {
      client.read();
    }

    client.stop();
    Serial.println("[Client disconnected]");
  }
}
(Figure. 6 Result from WebServer)

ESP8266WebServer class

From the example of making a web service machine, you will find that Programmers have to monitor incoming messages and parse to interpret what is received. For example, when found “GET / HTTP/1.1”, the client requests access to the root directory or homepage. If it is a request to another site, such as index9.html, it will become “GET /index9.html HTTP/1.1”. Therefore, the programmer will need to add a word-splitting section to ensure which resource the client is requesting. For this reason, there is a class ESP8266WebServer that allows programming to perform web services more conveniently.

From the previous example when writing with ESP8266WebServer, you will get the following code:

#include <DHT.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#define AP_NAME "JarutEx"
#define AP_PASSWD "123456789"
IPAddress myIP(192, 168, 4, 1);
IPAddress gwIP(192, 168, 4, 10);
IPAddress subnet(255, 255, 255, 0);

DHT dht = DHT(2, DHT11);
ESP8266WebServer server(80);


float minC = 100.0f, maxC = 0.0f; // max, min degree
float minH = 100.0f, maxH = 0.0f; // max, min humidity
float hic; // headt index  C
float hif;// headt index F
float h; // humidity
float tc; // Celcius degree 
float tf; // Fahrenheit degree

void getDHT11() {
  h = dht.readHumidity();
  tc = dht.readTemperature();
  tf = dht.readTemperature(true);

  if (isnan(h) || isnan(tc) || isnan(tf)) {
    h = -1.0f;
    tc = -1.0f;
    tf = -1.0f;
    hic = -1.0f;
    hif = -1.0f;
    return;
  }

  hic = dht.computeHeatIndex(tc, h, false);
  hif = dht.computeHeatIndex(tf, h);

  if (minC > tc) {
    minC = tc;
  }
  if (maxC < tc) {
    maxC = tc;
  }
  if (minH > h) {
    minH = h;
  }
  if (maxH < h) {
    maxH = h;
  }
}


void setup() {
dht.begin();
Serial.begin(115200);
Serial.println("\n\r\n\r");
  if (WiFi.softAPConfig( myIP, gwIP, subnet )) {
    if (WiFi.softAP(AP_NAME, AP_PASSWD, 8, false, 5)) {
      Serial.print("IP Address : ");
      Serial.println(WiFi.softAPIP());
    } else {
      while (true);
    }
  } else {
    while (true);
  }
  server.on("/", htmlPage);
  server.begin();
}

void htmlPage() {
  String html;
  getDHT11();
  html.reserve(2048);               // prevent ram fragmentation
  html = F(
           "<!DOCTYPE HTML>"
           "<html><head>"
           "<meta name='viewport' content='width=device-width, initial-scale=1'>"
           "<style>"
           "html {font-family: Arial; display: inline-block; text-align: center;}"
           "h1 {font-size: 3.0rem;}"
           "p {font-size: 3.0rem;}"
           "body {max-width: 800px; margin:0px auto; padding-bottom: 16px;}"
           "</style>"
           "</head><body>"
           "<h1>DHT11</h1>"
         );

  html += F("<div>Temperature:");
  html += tc;
  html += F("C/");
  html += tf;
  html += F("F</div>");
  html += F("<div>Huminity:");
  html += h;
  html += F("%</div>");
  html += F("<div>Temperature:");
  html += minC;
  html += F("C-");
  html += maxC;
  html += F("C</div>");
  html += F("<div>Huminity:");
  html += minH;
  html += F("%-");
  html += maxH;
  html += F("%</div>");
  html += F("</body></html>\r\n");
  server.send(200, "text/html", html);
}

void loop() {
  server.handleClient();
}

As an example, we have revised some of the HTML elements in CSS rendering controls to make the font more suitable for multiple devices. In terms of use the ESP8266WebServer is used instead of WiFiServer and only 3 main functions are left:

  1. Request Intercept Settings and reply
    1. By using server.on( resource, response function )
    2. In the response function call server.send( response code, datatype, data).
  2. Start it by calling server.begin() in setup()
  3. Waiting for requests from clients with calls server.handleClient() in loop()

Conclusion

From this article, we will find that if we understand the communication principles of different protocols, we can use the esp8266 microcontroller as a service or client to communicate with that protocol. As in this example, esp8266’s WiFiServer is used to intercept port 80, the HTTP protocol port, and when it encounters a message requesting a resource, we respond in a format that HTTP understands. Show results on the web browser correctly as shown in Figure 6. Finally, have fun with programming.

If you want to talk with us, feel free to leave comments below!

Reference

  1. ESP8266 Arduino Core :Server

(C) 2021, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2021-11-15