como-emplear-el-esp8266-como-cliente-http

Cómo emplear el ESP8266 o ESP32 como cliente HTTP

Continuamos con los tutoriales de la ESP8266 y el ESP32 viendo cómo emplear el ESP8266 como cliente HTTP.

Haremos referencia al ESP8266, pero el mismo código es compatible para el ESP32, ajustando el nombre de las librerías. Al final tenéis el código tanto para el ESP8266 como para el ESP32.

En entradas anteriores ya hemos visto cómo conectar el ESP8266 tanto en modo STA como modo AP, cómo configurar una IP estática, y cómo usar el mDNS. Ahora que ya sabemos conectar nuestro ESP8266, nos toca empezar a trabajar con él y sacarle partido.

Comenzamos viendo cómo usar el ESP8266 como cliente. Recordar que en una comunicación M2M (machine to machine) el cliente simplemente es el dispositivo que inicia la conexión. En las próximas entradas, nos adentraremos en su uso como servidor.

¿Para qué usar el ESP8266 como cliente?

Es muy frecuente encontrar proyectos en los que el ESP8266 actúa como servidor y otro dispositivo (un móvil, un ordenador, etc) actúa como cliente. Tanto, que a veces en muchos casos y tutoriales se tiende a olvidar la funcionalidad como cliente.

ESP8266-cliente-servidor

Entonces, ¿en qué situaciones es útil que el ESP8266 actúe como cliente? ¡En un montón! Recordar que el cliente es simplemente el dispositivo que inicia la comunicación. Vamos a citar algunos ejemplos.

Un ejemplo muy didáctico (aunque no especialmente realista) es el de obtener una página web para procesar/parsear el contenido de la página web en búsqueda de una cierta información. Ejemplos típicos son, por ejemplo, leer la hora, o la previsión del tiempo.

En casos más prácticos son, por ejemplo, obtener información proporcionada por un servidor que facilita al hacer la llamada a un endpoint/URL, por ejemplo, en formato CSV, JSON o XML.

Otro ejemplo real es lanzar una petición contra un endpoint de un cierto API (normalmente un API REST) para ejecutar una acción en un servidor remoto (encender una luz, abrir una puerta…)

Por último, como otro ejemplo real, podemos iniciar una conexión para enviar una información a un servidor para su tratamiento (por ejemplo, una Raspberry Pi) para que almacene el valor en una base de datos, calcule estadísticas, etc.

En definitiva, lo usaremos para comunicar con y transferir información a otro dispositivo (incluido entre dos ESP8266). Como vemos, no hay que infravalorar la funcionalidad del ESP8266 como cliente.

ESP8266 como cliente

Cómo viene siendo costumbre emplear el ESP8266 como cliente es realmente sencillo gracias a la librería ESP8266HTTPClient y el gran trabajo desarrollado por la comunidad.

Para iniciar la conexión cómo cliente empleamos la función http.begin(…), que requiere una instancia del objeto HTTPClient y WiFiClient, y admite las siguientes sobrecargas.

bool begin(WiFiClient &client, String url);
bool begin(WiFiClient &client, String host, uint16_t port, String uri = "/", bool https = false);

El método http.begin(…) devuelve true si la conexión se ha realizado con éxito. Una vez iniciada la conexión, podemos realizar una petición http, por ejemplo, http.GET();

En el caso del ESP32 la librería se llama ‘ESP8266HTTPClient’ se llama simplemente ‘HTTPClient’.

Ejemplo

Vamos a ver todo esto junto en un ejemplo. Y, cómo no, vamos a elegir el didáctico (aunque no muy útil) ejemplo de mostrar el contenido de una página web por puerto serie. Por ejemplo, de ’http://www.google.com‘.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

// Sustituir por los datos de vuestro WiFi
const char* ssid = "ssid";
const char* password = "password";
String url = "http://www.google.com";

void setup()
{
  Serial.begin(115200);
  delay(10);

  // Conectar WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
    delay(500);
}

void loop()
{
  HTTPClient http;
  WiFiClient client;

  if (http.begin(client, url)) //Iniciar conexión
  {
    Serial.print("[HTTP] GET...\n");
    int httpCode = http.GET();  // Realizar petición

    if (httpCode > 0) {
      Serial.printf("[HTTP] GET... code: %d\n", httpCode);

      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String payload = http.getString();  // Obtener respuesta
        Serial.println(payload);  // Mostrar respuesta por serial
      }
    }
    else {
      Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }

    http.end();
  }
  else {
    Serial.printf("[HTTP} Unable to connect\n");
  }

  delay(30000);
}

Si todo ha salido bien, veremos por el monitor serial un texto muy largo, que es el contenido de la página web de www.google.com.

esp8266-cliente-demo

¡Así de fácil! Por supuesto, la librería ESP8266HTTPClient tiene muchos más aspectos que comentar. A continuación, entraremos un poco más en detalle.

ESP8266HTTPClient en detalle

La clase HTTPClient es capaz de realizar otro tipo de peticiones HTTP, además de GET. Para ello tenemos los siguientes métodos.

int GET();
int POST(String payload);
int PUT(String payload);
int PATCH(String payload);

Cómo vemos, a excepción de GET, aceptan un String con el cuerpo de la petición. Estos métodos no son más que alias (‘sintaxis sugar’) para el método más general sendRequest(…)’, donde ‘type’ indica el tipo de petición a realizar (GET, POST, PUT…

int sendRequest(const char * type, String payload);

Usaremos el método general, por ejemplo, en peticiones DELETE, ya que echamos de menos un método directo para ejecutarlo, y es un verbo necesario para interactuar con un API REST.

Los métodos de petición devuelven integer con el código de respuesta de la petición. Recordar que estos códigos son estándar en HTTP y están divididos en familias:

  • 1xx: Informational
  • 2xx: Success
  • 3xx: Redirection
  • 4xx: Client Error
  • 5xx: Server Error

La librería define alias para los principales tipos de códigos de respuesta. Hay muchos tipos de códigos, pero algunos de los más habituales son.

CODEESP8266 AliasSignificado
200HTTP_CODE_OKOK
300HTTP_CODE_MULTIPLE_CHOICESMultiple Choices
301HTTP_CODE_MOVED_PERMANENTLYMoved Permanently
302HTTP_CODE_FOUNDFound
304HTTP_CODE_NOT_MODIFIEDNot Modified
400HTTP_CODE_BAD_REQUESTBad Request
401HTTP_CODE_UNAUTHORIZEDUnauthorized
403HTTP_CODE_FORBIDDENForbidden
404HTTP_CODE_NOT_FOUNDNot Found
410HTTP_CODE_GONEGone
500HTTP_CODE_INTERNAL_SERVER_ERRORInternal Server Error
501HTTP_CODE_NOT_IMPLEMENTEDNot Implemented
503HTTP_CODE_BAD_GATEWAYService Unavailable

También es posible añadir cabeceras en la petición con la función

void addHeader(const String& name, const String& value, bool first = false, bool replace = true);

Finalmente, remarcar que es posible emplear la función http.begin(…) sin emplear una instancia de WiFiClient con las siguientes sobrecargas

bool begin(String url)  __attribute__ ((deprecated));
bool begin(String host, uint16_t port, String uri = "/")  __attribute__ ((deprecated));

Aunque sea muy normal encontrarlo en tutoriales y proyectos, resaltar que estas funciones están obsoletas, y no permiten usar de los métodos y funcionalidades que proporciona la clase WiFiCliente.

Por si alguno se lo pregunta, no, el programa generado con estas funciones no es ni más pequeño ni más eficiente. De hecho, es al revés)

Ejemplo resumido

Para que el código sea más sencillo y cómodo, como es habitual en esta sección, vamos a dividir el código en archivos. A nuestros ya habituales ‘config.h’ y ‘ESP8266_Utils.hpp’ vamos a añadir lo siguiente

El programa principal queda reducido al siguiente código,

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

String url = "http://www.google.com";

#include "config.h"  // Sustituir con datos de vuestra red
#include "Client.hpp"
#include "ESP8266_Utils.hpp"
#include "ESP8266_Utils_Client.hpp"
 
void setup()
{
   Serial.begin(115200);
 
   ConnectWiFi_STA();
}
 
void loop()
{
   ClientRequest();
 
   delay(30000);
}

Un fichero ‘ESP8266_Utils_Client.hpp’ con el siguiente contenido,

void ClientRequest()
{
   if (http.begin(client, url)) //Iniciar conexión
   {
      Serial.print("[HTTP] GET...\n");
      int httpCode = http.GET();  // Realizar petición
 
      if (httpCode > 0) {
         Serial.printf("[HTTP] GET... code: %d\n", httpCode);
 
         if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
            String payload = http.getString();   // Obtener respuesta
            ProcessResponse(payload);
         }
      }
      else {
         Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }
 
      http.end();
   }
   else {
      Serial.printf("[HTTP} Unable to connect\n");
   }
 
}

Por otro lado creamos un fichero ‘Client.hpp’ que contendrá las funciones a ejecutar al obtener la respuesta. En este ejemplo, únicamente mostraremos por Serial la respuesta obtenida, por lo que el código es el siguiente.

void ProcessResponse(String response)
{
   Serial.println(response);   // Mostrar respuesta por serial
}

Hasta aquí el tutorial de cómo usar el ESP8266 como cliente. Por supuesto, hay muchas más funciones y constantes en la librería ESP8266HTTPClient. Si tenéis curiosidad consultar su código, es muy interesante su lectura.

En una futura entrada veremos cómo emplear estas funciones para consumir un API REST e interactuar con otros dispositivos. Pero será más adelante, cuando hayamos visto el resto de aspectos más básicos del ESP8266.

De momento, en la próxima entrada comenzaremos con el ESP8266 actuando como servidor. ¡Tenemos diversión para rato!

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github.

github-full

Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples