Asynchronous web server with ESP8266 module

This basic example of an asynchronous web server for use in the esp8266 loading it from the Sketch of arduino thanks to a firmware flashing we can reprogram it as if it were an atmega328p, and forgetting about the tedious AT commands as we do here flashing-esp8266-fu-k-at-commands we will use the DHT22 sensor which is much more accurate than its archenemy the DHT11, we will need a serial converter like the one contained in the arduino through TX/RX pins otherwise we would have to buy a very cheap usb-serial ttl converter.

These are brief characteristics of both sensors:

caracteristicasDHT11DHT22

DHT-22 pinout

DHT22 pins

MB102 adjustable power supply

We will use this 3.3v | 5v supply with an external 2000mAh transformer plus 12vc output. You can see on the power supply MB102, the jumper that allows us to get 3.3v, can be checked with a multimeter with alligator bits, and or needles.

A transformer of less than 6.5vdc will not be suitable for the MB102

fuenteregulableesp82663v5v

Without Fritzing

But this serves as a final view.

  • A 10Kohm resistor (many use 4.7k) as pull-up between DATA and VCC (3.3v).

  • I get the GND from the power supply.

lateral


Writing the asynchronous web server code (AsynchronousWebServer)

We will use the following libraries:

#include <ESP8266WiFi.h> (1)
#include <ESPAsyncTCP.h> (2)
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h> (3)
#include <DHTStable.h> (4)
1 For wifi connection (ESP8266WiFi)
2 For the asynchronous server as well as the ESPAsyncWebServer
3 Creation of the (ArduinoJson) json for the Rest api
4 Where <DHTStable.h> is a more up to date lib, and of the humidity and temperature sensor <DHTStable.h>
#define DHT22_PIN 4 (1)
DHTStable DHT;
1 We define the variables to use the DHT22 sensor pin.
AsyncWebServer server(8081); (1)
1 We set the server port to 8081, I have the other typical ones in use XD.
//Endpoints
const char* TEMPERATURES = "/async-esp8266/api/v1/dht22/temperatures"; (1)
const char* HUMIDITIES = "/async-esp8266/api/v1/dht22/humidities"; (2)
const char* LED_STATUS = "/async-esp8266/api/v1/led"; (3)
1 Temperature endpoints.
2 Humidity endpoints.
3 Endpoints for changing the led state.

Configuration of wifi network, we place name and password.

const char* ssid = "Tu red";
const char* password = "misuperhax0rpassword";
//esperando por conexión
while (WiFi.status() != WL_CONNECTED) { (1)
  delay(1000);
  Serial.println("Connecting to WiFi..");
}
1 While trying to connect to the wifi network, and notifying the console.
void loop(void) {
  DHT.read22(DHT22_PIN); (1)
  t = DHT.getTemperature();
  h = DHT.getHumidity();
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.println(HUMIDITY);
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.println(TMP);
  delay(2000); (2)
}
1 Here is the loop() function needed to read the sensor.
2 Set a delay of 2 seconds.

The initRoute function simply greets with a text greeting when visiting the main url /.

//Hello world!
void initRoute() {
   server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
        request -> send(OK_HTTP, TEXT_PLAIN, "Welcome webserver Esp8266");
   });
}

Temperature endpoint

/async-esp8266/api/v1/dht22/temperatures
//Temperaturesº
void temperatures() {
  server.on(TEMPERATURES, HTTP_GET, [](AsyncWebServerRequest * request) {
    String json;
    StaticJsonDocument<300> doc;
    doc["sensor"] = "DHT-22";
    doc["type"] = "AM2302";
    doc["temperature"] = t;
    serializeJson(doc, json);
    request -> send(OK_HTTP, APPLICATION_JSON, json);
  });
}

getTemperatures


Humidity endpoint

/async-esp8266/api/v1/dht22/humidities
//Humidities%
void humidities() {
  server.on(HUMIDITIES, HTTP_GET, [](AsyncWebServerRequest * request) {
    String json;
    StaticJsonDocument<300> doc;
    doc["sensor"] = "DHT-22";
    doc["type"] = "AM2302";
    doc["humidity"] = h;
    serializeJson(doc, json);
    request -> send(OK_HTTP, APPLICATION_JSON, json);
  });
}

getHumidities


The handeLED function will be used to see the state of the led, turn it on and off, typically updating it on pin 2 to HIGH or LOW, depending on the query parameters.

// On/off Led
void handleLED() { (1)
  //Show led status
  server.on(LED_STATUS, HTTP_GET, [](AsyncWebServerRequest * request) {
    ledstatus = digitalRead(LED_PIN);
    if (ledstatus == HIGH) {
      //status is ON
      request -> send(OK_HTTP, TEXT_PLAIN, "Status ON");
    } else {
      //status is Off
      request -> send(OK_HTTP, TEXT_PLAIN, "Status OFF");
    }
  });

  //async-esp8266/api/v1/led?id=2&newstatus=on //ON
  //async-esp8266/api/v1/led?id=2&newstatus=off //OFF
  server.on(LED_STATUS, HTTP_PUT, [](AsyncWebServerRequest * request) {
    String id = request-> arg("id"); (2)
    String newstatus = request-> arg("newstatus"); (3)
    if (id.toInt() == LED_PIN && newstatus.equalsIgnoreCase("on")) {
      Serial.println("PIN HIGH");
      digitalWrite(LED_PIN, HIGH);
      request -> send(OK_HTTP, TEXT_PLAIN, oK);
    } else if (id.toInt() == LED_PIN && newstatus.equalsIgnoreCase("off")) {
      Serial.println("PIN LOW");
      digitalWrite(LED_PIN, LOW);
      request -> send(OK_HTTP, TEXT_PLAIN, oK);
    } else {
      request -> send(400, TEXT_PLAIN, "Bad Request");
    }
  });
}
1 Function to manage the led control, it should be factored a little more, divide better in other functions.
2 We obtain the id of the led.
3 By means of the status, we turn it off or turn it on.

Complete code

Honestly looking at this now, after all this time, instead of using PUT, I would use the http PATCH method plus a body.

Endpoints

Operation URI

GET

/async-esp8285/api/v1/dht22

GET

/async-esp8285/api/v1/dht22/temperatures

GET

/async-esp8285/api/v1/dht22/humidities

PUT

/async-esp8285/api/v1/led

query-parameters ON

query-parameters OFF

led?id=2&newstatus=on

led?id=2&newstatus=off

/**
 *
 * Make simple Asynchronous webserver using DHT22 for log temperature and humidity.
 *
 */
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <DHTStable.h>
#define DHT22_PIN 4

DHTStable DHT;

AsyncWebServer server(8081);// Create a asynchronous webserver object that listens for HTTP request on port 8081

int led_status = 0;
float t = 0;
float h = 0;

const int LED_PIN = 2;
const int OK_HTTP = 200;

//Endpoints
const char* DHT22 = "/async-esp8285/api/v1/dht22";
const char* TEMPERATURES = "/async-esp8285/api/v1/dht22/temperatures";
const char* HUMIDITIES = "/async-esp8285/api/v1/dht22/humidities";
const char* LED = "/async-esp8285/api/v1/led";

const char* DHT_22 = "DHT-22";
const char* AM2302 = "AM2302";
const char* CENTIGRADE = "ºC";
const char* PERCENTAGE = "%";
const char* TEXT_PLAIN = "text/plain";
const char* APPLICATION_JSON = "application/json";
const char* ON = "ON";
const char* OFF = "OFF";
const char* ID = "id";
const char* NEW_STATUS = "status";
const char* SENSOR = "sensor";
const char* TYPE = "type";
const char* TEMPERATURE = "temperature";
const char* HUMIDITY = "humidity";

//Wifi network credentials
const char* ssid = "Filomena 2.4";
const char* password = "zAHF4n+MMHniN*G"; //aqui les dejo mi contraseña para que se conecten, wifi free :)

void setup(void) {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  delay(10);

  Serial.println('\n');
  WiFi.begin(ssid, password);

  //wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

  initRoute();
  temperatures();
  humidities();
  dht22();
  handleLED();
  handleNotFound();

  server.begin();// Actually start the server
  Serial.println("HTTP server started");
}

void loop(void) {
  DHT.read22(DHT22_PIN);
  t = DHT.getTemperature();
  h = DHT.getHumidity();
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.println(PERCENTAGE);
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.println(CENTIGRADE);
  delay(2000);
}

//Welcome webserver Esp8266!!!
void initRoute() {
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request -> send(OK_HTTP, TEXT_PLAIN, "Welcome webserver Esp8266");
  });
}

//Temperaturesª
void temperatures() {
  server.on(TEMPERATURES, HTTP_GET, [](AsyncWebServerRequest * request) {
    String json;
    StaticJsonDocument<300> doc;
    doc[SENSOR] = DHT_22;
    doc[TYPE] = AM2302;
    doc[TEMPERATURE] = t;
    serializeJson(doc, json);
    request -> send(OK_HTTP, APPLICATION_JSON, json);
  });
}

//Humidities%
void humidities() {
  server.on(HUMIDITIES, HTTP_GET, [](AsyncWebServerRequest * request) {
    String json;
    StaticJsonDocument<300> doc;
    doc[SENSOR] = DHT_22;
    doc[TYPE] = AM2302;
    doc[HUMIDITY] = h;
    serializeJson(doc, json);
    request -> send(OK_HTTP, APPLICATION_JSON, json);
  });
}

//DHT22 humidities% and temperaturesª
void dht22() {
  server.on(DHT22, HTTP_GET, [](AsyncWebServerRequest * request) {
    String json;
    StaticJsonDocument<300> doc;
    doc[SENSOR] = DHT_22;
    doc[TYPE] = AM2302;
    doc[TEMPERATURE] = t;
    doc[HUMIDITY] = h;
    serializeJson(doc, json);
    request -> send(OK_HTTP, APPLICATION_JSON, json);
  });
}

// On/off Led
void handleLED() {
  //Show led status
  server.on(LED, HTTP_GET, [](AsyncWebServerRequest * request) {
    led_status = digitalRead(LED_PIN);
    if (led_status == HIGH) {
      String json;
      StaticJsonDocument<300> doc;
      doc[ID] = LED_PIN;
      doc[NEW_STATUS] = ON;
      serializeJson(doc, json);
      request -> send(OK_HTTP, APPLICATION_JSON, json);
    } else {
      String json;
      StaticJsonDocument<300> doc;
      doc[ID] = LED_PIN;
      doc[NEW_STATUS] = OFF;
      serializeJson(doc, json);
      request -> send(OK_HTTP, APPLICATION_JSON, json);
    }
  });
  //async-esp8266/api/v1/led?id=2&status=on //ON
  //async-esp8266/api/v1/led?id=2&status=off //OFF
  server.on(LED, HTTP_PUT, [](AsyncWebServerRequest * request) {
    String id = request-> arg(ID);
    String new_status = request-> arg(NEW_STATUS);
    if (id.toInt() == LED_PIN && new_status.equalsIgnoreCase(ON)) {
      Serial.println("PIN HIGH");
      digitalWrite(LED_PIN, HIGH);
      String json;
      StaticJsonDocument<300> doc;
      doc[ID] = LED_PIN;
      doc[NEW_STATUS] = ON;
      serializeJson(doc, json);
      request -> send(OK_HTTP, APPLICATION_JSON, json);
    } else if (id.toInt() == LED_PIN && new_status.equalsIgnoreCase(OFF)) {
      Serial.println("PIN LOW");
      digitalWrite(LED_PIN, LOW);
      String json;
      StaticJsonDocument<300> doc;
      doc[ID] = LED_PIN;
      doc[NEW_STATUS] = OFF;
      serializeJson(doc, json);
      request -> send(OK_HTTP, APPLICATION_JSON, json);
    } else {
      request -> send(400, TEXT_PLAIN, "Bad Request");
    }
  });
}

//404
void handleNotFound() {
  //Error 404 not found
  server.onNotFound([](AsyncWebServerRequest * request) {
    request->send(404, TEXT_PLAIN, "Sorry, 404 not found.");
  });
}

// -- EOF --

With respect to safety

It would be a very good idea to add authentication and ssl certificates or forced redirection via https with a reverse-proxy nginx, so we don’t have to put so much code in the bug.