
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.
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…).
Anuncio:
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.
Para ello, 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"); }
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(); }
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
Anuncio:
Hola, muy bueno tu aporte y tienes una buena pagina, muchas gracias por tu esfuerzo, temgo una duda, esa ventana que muestras como envias el parametro POST Y GET como la obtienes?
Hola Jaime. Echa un ojo a esta entrada. Un saludo!
Buenas Luis excelente el tutorial. Solo una cosa, he visto que en la función setLED, al poner Serial.println(server.argName(0)); lo que aparece en el monitor serie es ‘Id’ literalmente y no se imprime el status. He eliminado esa instrucción y he añadido Serial.println(server.arg(0));
Serial.println(server.arg(1)); y entonces ya si imprime ’10’ y ‘ON’. Saludos.