Servidor web asíncrono con el módulo ESP8266.

Este ejemplo básico de un servidor web asíncrono para usarlo en el esp8266 cargándolo desde el Sketch de arduino gracias a que con un flasheo del firmware podemos reprogramarlo como si de un atmega328p se tratase, y olvidándonos de los tediosos comandos AT como hacemos aqui fu#k comandos at, usaremos el sensor DHT22 que es mucho más preciso que su archienemigo el DHT11, necesitaremos un conversor serial como el que contiene el arduino por medio de los pines tx/rx si no tendríamos que comprar un conversor usb-serial ttl muy económicos.

Estas son breves característica de ambos sensores:

image

DHT-22 pinout

image

Fuente regulable MB102

Usaremos esta fuente de 3.3v | 5v con un transformador externo de 2000mAh más salida de 12vc. Se ve en la fuente de poder MB102, el jumper que nos permite obtener 3.3v, se puede comprobar con un multímetro con puntas de caiman, y o agujas.

Un transformador de menos de 6.5vdc no servirá para la MB102

image

> Sin Fritzing

Pero esto sirve como vista final.

  • Una resistencia de 10Kohm( muchos usan 4.7k ) como pull-up entre el DATA y VCC(3.3v)
  • La GND la obtengo de la fuente de poder.

image


Escribiendo el código del servidor web asíncrono (AsynchronousWebServer)

Usaremos las librerías siguientes:

  • Donde <DHTStable.h> es una lib más actual.
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <DHTStable.h>

Hay están contenidas para cada caso, para la conexión wifi (ESP8266WiFi), servidor asíncrono (ESPAsyncTCP, ESPAsyncWebServer) creación del json (ArduinoJson) para la api Rest, y del sensor de humedad y temperatura <DHTStable.h>

Definimos las variables para usar el pin del sensor DHT22

#define DHT22_PIN 4
DHTStable DHT;

Definimos el puerto del servidor en el 8081, tengo los otros típicos en uso XD

AsyncWebServer server(8081);

Definimos nuestros endpoints

//Endpoints
const char* TEMPERATURES = "/async-esp8266/api/v1/dht22/temperatures";
const char* HUMIDITIES = "/async-esp8266/api/v1/dht22/humidities";
const char* LED_STATUS = "/async-esp8266/api/v1/led";

Configuración de red wifi, colocamos nombre y password.

const char* ssid = "Tu red";
const char* password = "misuperhax0rpassword";

Se intentara conectar a la red wifi, y notificara por la consola.

//esperando por conexión
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.println("Connecting to WiFi..");
}

Aqui la función loop() necesaria para hacer la lectura del sensor, y colocar un delay de 2 segundos

void loop(void) {
  DHT.read22(DHT22_PIN);
  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);
}

la función initRoute simplemente saluda con un texto al visitar la url principal /

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

Endpoint de temperatura

/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);
  });
}

image

Endpoint de humedad

/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);
  });
}

image

La función handeLED la usaremos para ver el estado del led, prender y apagarlo, lo típico actualizaremos en el pin 2 a HIGH o LOW, dependiendo el query parameters.

// On/off Led
void handleLED() {
  //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");
    String newstatus = request-> arg("newstatus");
    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");
    }
  });
}

Código completo

/**
 * 
 * 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 --

Enlaces de interes

Comments