Segunda entrada dedicada al ESP8266 y el ESP32 como servidor. En esta ocasión vamos a profundizar en el tratamiento de distintos tipos de peticiones, y la obtención de parámetros.
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 la entrada anterior vimos cómo montar un servidor con el ESP8266, adelantando que nos iba a ocupar unas cuantas entradas. Anteriormente habíamos visto cómo usar el ESP8266 como cliente.
Al ver el servidor web en la entrada anterior únicamente usamos métodos (request) de tipo GET. Y hasta ahí se quedarían muchos tutoriales de Internet. Pero a nosotros nos gusta meternos en un poco más de profundidad ¿A que sí?
Para ello vamos a ver los distintos tipos de peticiones y sus parámetros. Como habíamos visto, una petición HTTP puede ser de distintos tipos (GET, POST, PATH, DELETE…).
Hace mucho tiempo, cuando internet “era joven”, había mucha confusión sobre para que servían los distintos tipos de funciones. Pero en esta era API REST e interface M2M, debería estar muy claro el motivo por el que existen distintos tipos peticiones. Típicamente cada tipo se corresponde con ‘acciones’ que quieres realizar en el servidor.
Así que lo lógico es que la petición HTTP que te dice si un LED está encendido sea de tipo GET. Pero la que lo enciende y apaga lo correcto sería usar un PATCH (como mucho, se podría pasar un POST).
Para entender las peticiones y qué acción quieren que hagamos, no vale con routear un URI a una acción de callback, sino que además debemos poder lanzar acciones distintas en función del tipo de petición que recibimos.
De forma similar tenemos los parámetros. Recordar que en una petición HTTP podemos mandar parámetros, bien en la URL (en peticiones GET) o codificado de alguna de las diversas formas en el cuerpo de la petición.
Diferenciar tipo de petición
Para diferenciar el tipo de petición la librería ESP8266WebServer dispone de la sobrecarga del método ‘on(…)’, que permite indicar el método que necesitamos
void on(const String &uri, HTTPMethod method, THandlerFunction fn);
Siendo,
- URI, dirección del recurso.
- method, el método que queremos asociar (HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS)
- fn, la función de callback a ejecutar.
Obtener parámetros
Por otro lado, para obtener los parámetros la librería ESP8266WebServer dispone de los siguientes métodos.
const String& arg(String name) const; // get request argument value by name
const String& arg(int i) const; // get request argument value by number
const String& argName(int i) const; // get request argument name by number
int args() const; // get arguments count
bool hasArg(const String& name) const; // check if argument exists
Veamos un ejemplo
Como siempre, lo mejor es verlo en un ejemplo sencillo. Supongamos que tenemos un ESP8266 con una serie de LED, que identificamos por su ID. Por un lado, queremos poder consultar el estado de cada LED y, además, queremos poder encender o apagar el LED.
Primero, vamos a ver como NO se hace. Lo que no se hace, es emplear una petición GET tanto encender y apagar el LED, ni se hacen “cosas raras” con la clase String para crear una petición a una URI con la siguiente forma.
/led?Id=10&Status=ON
No, eso no se hace. Lo correcto, es hacer dos routeos. Uno de tipo GET a la URI ‘/led’ que reciba el ID del LED que queremos consultar, y uno de tipo POST que reciba el ID del LED, y su nuevo estado.
Esto, lo podríamos hacer de la siguiente forma, donde simplemente creamos dos routeos y le asociamos una función que, en este ejemplo, simplemente muestra los parámetros recibidos.
El programa principal no ha variado respecto a la entrada anterior, que recordemos era,
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
#include "config.h" // Sustituir con datos de vuestra red
#include "ESP8266_Utils.hpp"
#include "Server.hpp"
void setup(void)
{
Serial.begin(115200);
ConnectWiFi_STA();
InitServer();
}
void loop()
{
server.handleClient();
}
Modificamos el fichero ‘Server.hpp’ que creamos en la entrada anterior con el siguiente contenido
// Funcion al recibir petición GET
void getLED()
{
// devolver respuesta
server.send(200, "text/plain", String("GET ") + server.arg(String("Id")));
}
// Funcion al recibir petición POST
void setLED()
{
// mostrar por puerto serie
Serial.println(server.argName(0));
// devolver respuesta
server.send(200, "text/plain", String("POST ") + server.arg(String("Id")) + " " + server.arg(String("Status")));
}
// Funcion que se ejecutara en la URI '/'
void handleRoot()
{
server.send(200, "text/plain", "Hola mundo!");
}
void handleNotFound()
{
server.send(404, "text/plain", "Not found");
}
void InitServer()
{
// Ruteo para '/'
server.on("/", handleRoot);
// Definimos dos routeos
server.on("/led", HTTP_GET, getLED);
server.on("/led", HTTP_POST, setLED);
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
Resultado
Ahora, si usamos un Postman para lanzar las peticiones al ESP8266 y comprobar que estamos leyendo correctamente el tipo y parámetro de la petición.
Para la petición GET haríamos,
Y para la petición POST tendríamos,
En este ejemplo, también veríamos en el puerto serie la petición. En un caso real, realizaríamos las acciones oportunas (en este caso, seguramente encender o apagar el LED).
Hasta aquí por hoy. Hemos aprendido a leer el tipo y los parámetros de una petición HTTP desde un ESP8266 cuando este actúa como servidor. Aunque de momento, únicamente devolvemos respuestas sencillas.
En la próxima entrada ampliaremos nuestro servidor, comenzando a servidor contenidos más complicados, típicamente una página web. ¡Hasta pronto!
Descarga el código
Todo el código de esta entrada está disponible para su descarga en Github.
Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples
Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples