Neste post, será demonstrado como desenvolver um WebServer assíncrono utilizando o microcontrolador ESP32 e a maioria dos algoritmos para controle de um WebServer assíncrono. Por fim, será desenvolvido um projeto para que o ESP32 procure as redes WiFi disponíveis e exiba, em uma página web, utilizando o WebServer Assíncrono, os dados das redes.
Um servidor WebServer assíncrono é um tipo de servidor que pode manipular solicitações de forma escalável, em que as solicitações HTTP dos clientes não bloqueiam umas às outras e são executadas simultaneamente.
Em servidores baseados em threads tradicionais, para cada cliente há uma thread separada dedicada para atende-lo. Este comportamento pode provocar problemas de bloqueio quando um servidor está esperando que o processo libere recursos.
Já em servidores web assíncronos, há um processo de trabalho que aceita solicitações HTTP de todos os clientes e processa as solicitações dos clientes usando loops eficientes orientados a eventos. Este tipo de comportamento não causa problemas de bloqueio, como o outro tipo de servidor.
Neste post, construiremos um WebServer utilizando uma biblioteca chamada ESPAsyncWebServer, feita pelo desenvolvedor me-no-dev. Esta biblioteca não é disponibilizada no gerenciador de bibliotecas do IDE Arduino. Por isso, é necessário baixa-la como um arquivo .zip e instala-la manualmente. O passo a passo da instalação da biblioteca estará no tópico Instalação das bibliotecas. O repositório e a documentação da biblioteca pode ser acessada neste link.
Entretanto, a biblioteca ESPAsyncWebServer necessita de outra biblioteca para seu funcionamento: a AsyncTCP. Esta é uma biblioteca TCP totalmente assíncrona, destinada a permitir um ambiente de rede multiconexão sem problemas para os Microcontroladores ESP32, da Espressif. Ela também não é disponibilizada no gerenciador de bibliotecas do IDE Arduino e, por isso, é necessário baixa-la como um arquivo .zip e instala-la manualmente. O passo a passo da instalação da biblioteca estará no tópico Instalação das bibliotecas. O repositório da biblioteca pode ser acessada neste link.
Para instalar as bibliotecas no Arduino IDE, é necessário fazer download dos arquivos .zip das bibliotecas ESPAsyncWebServer e AsyncTCP.
PlatformIO IDE é um ecossistema de código aberto para desenvolvimento de IoT com sistema de compilação de plataforma cruzada, gerenciador de biblioteca e com suporte total para desenvolvimento Espressif ESP8266/ESP32. Para mais detalhes, consulte o post Como Programar o Arduino com VS Code e PlatformIO, aqui, mesmo, no blog Eletrogate:
Para instalação da biblioteca ESPAsyncWebServer, siga os passos abaixo:
Usar esta biblioteca como WebServer Assíncrono tem muitos benefícios, como os citados abaixo:
Mesmo tendo bastante benefícios, a biblioteca possui algumas limitações, citadas abaixo:
Para todos os algoritmos deste post, é utilizado somente o seguinte hardware (um Módulo WiFi ESP32 Bluetooth 30 pinos):
Todos os algoritmos deste post foram testados pelo navegador Google Chrome. Para se descobrir o IP para acessar a página do ESP32, deve-se acessar a página do roteador para ver os dispositivos conectados e ver qual é o IP do ESP32.
Nota: Para que os algoritmos deste post funcionem, substitua <SSID>
com o SSID da sua rede e substitua <SENHA>
com a senha da sua rede.
Para a maioria dos usos do ESP32 como WebServer Assíncrono, tem-se o seguinte algoritmo:
Primeiro, é necessário incluir as bibliotecas no sketch:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h>
Também é necessário instanciar um objeto da classe AsyncWebServer:
// Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80);
Ainda antes do void setup(), é necessário criar as constantes que armazenarão as credencias de acesso à rede sem fio (WiFi):
// Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<PASSWORD>";
Em void setup(), é conectado ao Ponto de Acesso com as credenciais fornecidas::
// Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password);
Por fim, dentro do void setup(), é definido que o servidor comece a ouvir os clientes:
// Servidor começa à ouvir os clientes server.begin();
Ficando assim o algoritmo básico de uso do ESP32 como WebServer Assíncrono:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<PASSWORD>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
O seguinte algoritmo responde à solicitação do cliente com conteúdo de string:
// Algoritmo: request->send(200, "text/plain", "Ola mundo!");
Onde a função send()
tem os seguintes parâmetros:
int code
: o código HTTP de status da resposta. Acesse, neste link, a lista de códigos HTTP.const String& contentType=String()
: Tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types.const String& content=String()
: o conteúdo da resposta.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" com o conteúdo da String abaixo server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(200, "text/plain", "Ola mundo!"); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
O seguinte algoritmo responde à solicitação do cliente com conteúdo de string e cabeçalhos extras:
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Ola mundo!"); response->addHeader("Server","ESP Async Web Server"); request->send(response);
Onde a função beginResponse()
tem os seguintes parâmetros:
int code
: o código HTTP de status da resposta. Acesse, neste link, a lista de códigos HTTP.const String& contentType=String()
: Tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types.const String& content=String()
: o conteúdo da resposta.a função addHeader()
tem os seguintes parâmetros:
const String& name
: o nome do cabeçalho HTTP;const String& value
: o conteúdo do cabeçalho HTTP.e, por fim, a função send()
tem os seguintes parâmetros:
AsyncWebServerResponse *response
: objeto usado para enviar os dados de resposta de volta ao cliente.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" com o conteúdo da String abaixo server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Ola mundo!"); // objeto criado para enviar os dados de resposta de volta ao cliente response->addHeader("Server","ESP Async Web Server"); // Adiciona um Cabeçalho HTTP request->send(response); // Envia a resposta }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
Ao clicar na tecla F12 (Google Chrome DevTools), é possível ver o cabeçalho de resposta enviado.
Um dos seguintes algoritmos responde à solicitação do cliente redirecionando-o para outro URL:
// Algoritmo: request->redirect("/page2");
ou
// Algoritmo: request->redirect("https://google.com");
Onde a função redirect()
tem os seguintes parâmetros:
const String& url
: o endereço (local ou externo) para redirecionar o cliente.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->redirect("/page2"); // redireciona para page2 }); // disponibiliza o url "/page2" server.on("/page2", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(200, "text/plain", "Voce esta na page2!"); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe um código HTTP:
request->send(503); // Envia código 503 (O servidor não está pronto para manipular a requisição)
Onde a função send()
tem os seguintes parâmetros:
int code
: o código HTTP de status da resposta. Acesse, neste link, a lista de códigos HTTP.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(503); // Envia código 503 (O servidor não está pronto para manipular a requisição) }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe um código HTTP e cabeçalhos extras:
AsyncWebServerResponse *response = request->beginResponse(404); // objeto criado para enviar os dados de resposta de volta ao cliente response->addHeader("Server","ESP Async Web Server"); // Adiciona um Cabeçalho HTTP request->send(response); // Envia a resposta
Onde a função beginResponse()
tem o seguinte parâmetro:
int code
: o código HTTP de status da resposta. Acesse, neste link, a lista de códigos HTTP.a função addHeader()
tem os seguintes parâmetros:
const String& name
: o nome do cabeçalho HTTP;const String& value
: o conteúdo do cabeçalho HTTP.e, por fim, a função send()
tem os seguintes parâmetros:
AsyncWebServerResponse *response
: objeto usado para enviar os dados de resposta de volta ao cliente.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { AsyncWebServerResponse *response = request->beginResponse(503); // objeto criado para enviar os dados de resposta de volta ao cliente response->addHeader("Server", "ESP Async Web Server"); // Adiciona um Cabeçalho HTTP request->send(response); // Envia a resposta }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
Ao clicar na tecla F12 (Google Chrome DevTools), é possível ver o cabeçalho de resposta enviado.
O seguinte algoritmo responde à solicitação do cliente enviando-lhe uma página grande da memória FLASH:
const char index_html[] PROGMEM = "..."; // grande matriz de caracteres request->send_P(200, "text/html", index_html); // Envia a resposta
Onde a função send_P()
tem o seguinte parâmetro:
int code
: o código HTTP de status da resposta. Acesse, neste link, a lista de códigos HTTP;const String& contentType=String()
: Tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types.PGM_P content
: o conteúdo para envio, proveniente de uma variável constante do tipo array de char que tenha um modificador PROGMEM. Este modificador permite armazenar dados na memória flash (memória de programa) em vez da SRAM. Gostaria de saber mais sobre PROGMEM? Acesse o artigo Progmem – Economizando Memória do Microcontrolador, aqui mesmo, no blog Eletrogate;AwsTemplateProcessor callback=nullptr
: parâmetro opcional para processar conteúdo contendo modelos.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { const char index_html[] PROGMEM = R"====( <html> <head> <meta charset='utf-8'/> </head> <body> <h1> Arduino </h1> <p> Arduino é uma plataforma de prototipagem eletrônica de hardware livre e de placa única, projetada com um microcontrolador Atmel AVR com suporte de entrada/saída embutido, uma linguagem de programação padrão, a qual tem origem em Wiring, e é essencialmente C/C++. O objetivo do projeto é criar ferramentas que são acessíveis, com baixo custo, flexíveis e fáceis de se usar por principiantes e profissionais. Principalmente para aqueles que não teriam alcance aos controladores mais sofisticados e ferramentas mais complicadas. </p> <p> Pode ser usado para o desenvolvimento de objetos interativos independentes, ou ainda para ser conectado a um computador hospedeiro. Uma típica placa Arduino é composta por um controlador, algumas linhas de E/S digital e analógica, além de uma interface serial ou USB, para interligar-se ao hospedeiro, que é usado para programá-la e interagi-la em tempo real. A placa em si não possui qualquer recurso de rede, porém é comum combinar um ou mais Arduinos deste modo, usando extensões apropriadas chamadas de shields. A interface do hospedeiro é simples, podendo ser escrita em várias linguagens. A mais popular é a Processing, mas outras que podem comunicar-se com a conexão serial são: Max/MSP, Pure Data, SuperCollider, ActionScript e Java. Em 2010 foi realizado um documentário sobre a plataforma chamado Arduino: The Documentary. </p> <figure> <img src='https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Arduino-uno-perspective-transparent.png/681px-Arduino-uno-perspective-transparent.png' width='300px'> <figcaption> Arduino versão Uno. Créditos: Wikipedia </figcaption> </figure> <p> O nome Arduino vem de um bar em Ivrea, Itália, onde alguns dos fundadores do projeto costumavam se reunir. O bar foi nomeado após Arduíno de Ivrea, que foi o marquês da Marca de Ivrea e Rei da Itália de 1002 a 1014. </p> <p> Fonte: <a href='https://pt.wikipedia.org/wiki/Arduino' target='_blank'>https://pt.wikipedia.org/wiki/Arduino</a> </p> </body> <html> )===="; // grande matriz de caracteres request->send_P(200, "text/html", index_html); // Envia a resposta }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
No algoritmo acima, foi utilizado o recurso de “Raw String Literal”: R"delimitador( . . . . )delimitador"
. Aqui, o delimitador é opcional e pode ser um caractere, exceto a barra invertida /
, espaços em branco
e parênteses ()
. Este recurso da linguagem C++ permite uma string na qual os caracteres de escape como \n
, \t
ou \
de C++ não são processados pelo compilador. Isto faz com que uma série de caracteres sejam passadas precisamente como sequência de caracteres brutos.
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe uma página grande código da memória FLASH juntamente com cabeçalhos HTTP extras:
const char index_html[] PROGMEM = "..."; // grande matriz de caracteres AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html); // objeto criado para enviar os dados de resposta de volta ao cliente response->addHeader("Server","ESP Async Web Server"); // Adiciona um Cabeçalho HTTP request->send(response); // Envia a resposta
Onde a função beginResponse_P()
tem o seguinte parâmetro:
int code
: o código HTTP de status da resposta. Acesse, neste link, a lista de códigos HTTP;const String& contentType=String()
: Tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types.PGM_P content
: o conteúdo para envio, proveniente de uma variável constante do tipo array de char que tenha um modificador PROGMEM. Este modificador permite armazenar dados na memória flash (memória de programa) em vez da SRAM. Gostaria de saber mais sobre PROGMEM? Acesse o artigo Progmem – Economizando Memória do Microcontrolador, aqui mesmo, no blog Eletrogate;AwsTemplateProcessor callback=nullptr
: parâmetro opcional para processar conteúdo contendo modelos.a função addHeader()
tem os seguintes parâmetros:
const String& name
: o nome do cabeçalho HTTP;const String& value
: o conteúdo do cabeçalho HTTP.e, por fim, a função send()
tem os seguintes parâmetros:
AsyncWebServerResponse *response
: objeto usado para enviar os dados de resposta de volta ao cliente.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { const char index_html[] PROGMEM = R"====( <html> <head> <meta charset='utf-8'/> </head> <body> <h1> Arduino </h1> <p> Arduino é uma plataforma de prototipagem eletrônica de hardware livre e de placa única, projetada com um microcontrolador Atmel AVR com suporte de entrada/saída embutido, uma linguagem de programação padrão, a qual tem origem em Wiring, e é essencialmente C/C++. O objetivo do projeto é criar ferramentas que são acessíveis, com baixo custo, flexíveis e fáceis de se usar por principiantes e profissionais. Principalmente para aqueles que não teriam alcance aos controladores mais sofisticados e ferramentas mais complicadas. </p> <p> Pode ser usado para o desenvolvimento de objetos interativos independentes, ou ainda para ser conectado a um computador hospedeiro. Uma típica placa Arduino é composta por um controlador, algumas linhas de E/S digital e analógica, além de uma interface serial ou USB, para interligar-se ao hospedeiro, que é usado para programá-la e interagi-la em tempo real. A placa em si não possui qualquer recurso de rede, porém é comum combinar um ou mais Arduinos deste modo, usando extensões apropriadas chamadas de shields. A interface do hospedeiro é simples, podendo ser escrita em várias linguagens. A mais popular é a Processing, mas outras que podem comunicar-se com a conexão serial são: Max/MSP, Pure Data, SuperCollider, ActionScript e Java. Em 2010 foi realizado um documentário sobre a plataforma chamado Arduino: The Documentary. </p> <figure> <img src='https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Arduino-uno-perspective-transparent.png/681px-Arduino-uno-perspective-transparent.png' width='300px'> <figcaption> Arduino versão Uno. Créditos: Wikipedia </figcaption> </figure> <p> O nome Arduino vem de um bar em Ivrea, Itália, onde alguns dos fundadores do projeto costumavam se reunir. O bar foi nomeado após Arduíno de Ivrea, que foi o marquês da Marca de Ivrea e Rei da Itália de 1002 a 1014. </p> <p> Fonte: <a href='https://pt.wikipedia.org/wiki/Arduino' target='_blank'>https://pt.wikipedia.org/wiki/Arduino</a> </p> </body> <html> )===="; // grande matriz de caracteres AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html);// objeto criado para enviar os dados de resposta de volta ao cliente response->addHeader("Server","ESP Async Web Server"); // Adiciona um Cabeçalho HTTP request->send(response); // Envia a resposta }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe uma página grande código da memória FLASH contendo modelos:
String processor(const String& var) { if(var == "OLA_PARA_MODELO") return "Olá mundo!"; return String(); } // ... const char index_html[] PROGMEM = "..."; // grande matriz de caracteres request->send_P(200, "text/html", index_html, processor);
Onde temos uma função chamada processor
, devendo ter o seguinte parâmetro obrigatório:
const String& var
: variável em que será recebido o nome (valor) do modelo à ser substituído.Dentro da função processor
, temos a (ou as) condicional que irá verificar se a variável var
tem um valor especifico informado. Caso tenha, é retornado o valor para substituição.
A função send_P()
tem o seguinte parâmetro:
int code
: o código HTTP de status da resposta. Acesse, neste link,a lista de códigos HTTP;const String& contentType
: Tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types;PGM_P content
: o conteúdo para envio, proveniente de uma variável constante do tipo array de char que tenha um modificador PROGMEM. Este modificador permite armazenar dados na memória flash (memória de programa) em vez da SRAM. Gostaria de saber mais sobre PROGMEM? Acesse o artigo Progmem – Economizando Memória do Microcontrolador aqui mesmo do blog Eletrogate;AwsTemplateProcessor callback=nullptr
: parâmetro para processar conteúdo contendo modelos.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; String processor(const String& var) { if(var == "OLA_PARA_MODELO") return "Olá mundo!"; return String(); } void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { const char index_html[] PROGMEM = R"====( <html> <head> <meta charset='utf-8'/> </head> <body> <h1> Teste </h1> <p> Mensagem %OLA_PARA_MODELO% recebida. </p> </body> <html> )===="; // grande matriz de caracteres request->send_P(200, "text/html", index_html, processor); // Envia a resposta }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Para a substituição do modelo funcionar, deve-se inserir, no conteúdo a ser enviado, o nome do modelo entre dois símbolos de Porcentagem (%
). O conteúdo a ser enviado não deve conter o símbolo de porcentagem (%
) sozinho em outros locais, pois isso iria “quebrar” o código.
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe uma página grande código da memória FLASH contendo modelos e cabeçalhos HTTP extras:
String processor(const String& var) { if(var == "OLA_PARA_MODELO") return "Olá mundo!"; return String(); } // ... const char index_html[] PROGMEM = "..."; // grande matriz de caracteres AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html, processor); // objeto criado para enviar os dados de resposta de volta ao cliente response->addHeader("Server","ESP Async Web Server"); // Adiciona um Cabeçalho HTTP request->send(response); // Envia a resposta
Onde temos uma função chamada processor
, devendo ter o seguinte parâmetro obrigatório:
const String& var
: variável em que será recebido o nome (valor) do modelo a ser substituído.Dentro da da função processor
, temos a (ou as) condicional que irá verificar se a variável var
tem um valor especifico informado. Caso tenha, é retornado o valor para substituição.
A função beginResponse_P()
tem o seguinte parâmetro:
int code
: o código HTTP de status da resposta. Acesse, neste link, a lista de códigos HTTP;const String& contentType
: Tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types;PGM_P content
: o conteúdo para envio, proveniente de uma variável constante do tipo array de char que tenha um modificador PROGMEM. Este modificador permite armazenar dados na memória flash (memória de programa) em vez da SRAM. Gostaria de saber mais sobre PROGMEM? Acesse o artigo Progmem – Economizando Memória do Microcontrolador aqui mesmo do blog Eletrogate;AwsTemplateProcessor callback=nullptr
: parâmetro opcional para processar conteúdo contendo modelos.E, a função addHeader()
tem os seguintes parâmetros:
const String& name
: o nome do cabeçalho HTTP;const String& value
: o conteúdo do cabeçalho HTTP.E, por fim, a função send()
tem os seguintes parâmetros:
AsyncWebServerResponse *response
: objeto usado para enviar os dados de resposta de volta ao cliente.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; String processor(const String& var) { if(var == "OLA_PARA_MODELO") return "Olá mundo!"; return String(); } void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { const char index_html[] PROGMEM = R"====( <html> <head> <meta charset='utf-8'/> </head> <body> <h1> Teste </h1> <p> Mensagem %OLA_PARA_MODELO% recebida. </p> </body> <html> )===="; // grande matriz de caracteres AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html, processor); // objeto criado para enviar os dados de resposta de volta ao cliente response->addHeader("Server","ESP Async Web Server"); // Adiciona um Cabeçalho HTTP request->send(response); // Envia a resposta }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
Os seguintes algoritmos respondem à solicitação do cliente enviando-lhe uma página com conteúdo vindo de um arquivo armazenado na SPIFFS:
//Envia página /index.html com tipo de conteúdo padrão request->send(SPIFFS, "/index.html");
ou
//Envia página /index.html como texto request->send(SPIFFS, "/index.html", "text/plain");
ou
// Disponibiliza a página /index.html para download request->send(SPIFFS, "/index.html", String(), true);
Onde as funções send()
tem os seguintes parâmetros:
FS &fs
: o tipo do Filesystem (normalmente, é usado o SPIFFS);const String& path
: o caminho do arquivo no diretório do Filesystem;const String& contentType=String()
: o tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types.bool download=false
: se o arquivo vai, ou não, ser disponibilizado para download direto;AwsTemplateProcessor callback=nullptr
: parâmetro opcional para processar conteúdo contendo modelos.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include <FS.h> #include <SPIFFS.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); if(!SPIFFS.begin(true)){ Serial.println("Ocorreu um erro ao montar SPIFFS"); return; } // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { // Disponibiliza a página /index.html request->send(SPIFFS, "/index.html"); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Para este exemplo de algoritmo funcionar, deve-se fazer o upload de um arquivo chamado index.html
para a SPIFFS. Para o passo a passo sobre como fazer isso, consulte o post SPIFFS: Armazenamento de Arquivos do ESP32, aqui mesmo, no blog Eletrogate.
O arquivo index.html
continha o seguinte conteúdo:
<html> <head> <meta charset='utf-8'/> </head> <body> <h1> ESP32 </h1> <p> ESP32 é uma série de microcontroladores de baixo custo e baixo consumo de energia. </p> </body> <html>
Resultado:
Os seguintes algoritmos respondem à solicitação do cliente enviando-lhe uma página com conteúdo vindo de um arquivo armazenado na SPIFFS juntamente com cabeçalhos HTTP extras:
// Envie index.html com o tipo de conteúdo padrão AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm"); response->addHeader("Server","ESP Async Web Server"); request->send(response);
ou
// Enviar index.html como texto AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", "text/plain"); response->addHeader("Server","ESP Async Web Server"); request->send(response);
ou
// Baixar index.html AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", String(), true); response->addHeader("Server","ESP Async Web Server"); request->send(response);
A função beginResponse_P()
tem os seguinte parâmetro:
FS &fs
: o tipo do Filesystem (normalmente é usado o SPIFFS);const String& path
: o caminho do arquivo no diretório do Filesystem;const String& contentType=String()
: o tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types.bool download=false
: se o arquivo vai, ou não, ser disponibilizado para download direto;AwsTemplateProcessor callback=nullptr
: parâmetro opcional para processar conteúdo contendo modelos.a função addHeader()
tem os seguintes parâmetros:
const String& name
: o nome do cabeçalho HTTP;const String& value
: o conteúdo do cabeçalho HTTP.e, por fim, a função send()
tem os seguintes parâmetros:
AsyncWebServerResponse *response
: objeto usado para enviar os dados de resposta de volta ao cliente.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include <FS.h> #include <SPIFFS.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); if(!SPIFFS.begin(true)){ Serial.println("Ocorreu um erro ao montar SPIFFS"); return; } // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { // Enviar index.html como página html AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.html", "text/html"); response->addHeader("Server","ESP Async Web Server"); request->send(response); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe uma página com conteúdo proveniente da SPIFFS e contendo modelos:
String processor(const String& var) { if(var == "OLA_FROM_TEMPLATE") return "Arduino e ESP32!"; return String(); } // ... //Envia página index.html com função de processador de modelo request->send(SPIFFS, "/index.html", String(), false, processor);
Onde, na função send()
, tem os seguinte parâmetro:
FS &fs
: o tipo do Filesystem (normalmente é usado o SPIFFS);const String& path
: o caminho do arquivo no diretório do Filesystem;const String& contentType=String()
: o tipo de mídia da Internet (Media type). Acesse, neste link, a lista de MIME types.bool download=false
: se o arquivo vai, ou não, ser disponibilizado para download direto;AwsTemplateProcessor callback=nullptr
: parâmetro para processar conteúdo contendo modelos.Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include <FS.h> #include <SPIFFS.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; String processor(const String& var) { if(var == "OLA_FROM_TEMPLATE") return "Arduino e ESP32!"; return String(); } void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); if(!SPIFFS.begin(true)){ Serial.println("Ocorreu um erro ao montar SPIFFS"); return; } // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { // Enviar index.html como página html request->send(SPIFFS, "/index.html", "text/html"); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Na SPIFFS, o arquivo index.html
possui o seguinte conteúdo:
<html> <head> <meta charset = "utf-8"> </head> <body> <h1>Teste com ESP32</h1> <p> A mensagem %OLA_FROM_TEMPLATE% foi recebida.</p> </body> </html>
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe uma página com conteúdo enviado através de print’s:
AsyncResponseStream* response = request->beginResponseStream("text/html"); response->print("<p>Ola<p/>"); String variavelQualquer = "mundo!"; response->printf("<p>Olá %s</p>", variavelQualquer); //envie a resposta por último request->send(response);
Onde, na função printf()
, tem os seguintes parâmetros:
const char * format, ...
: Cadeia de caracteres que contém o texto a ser passado para ser impresso. Opcionalmente, pode conter especificadores de formato incorporados que são substituídos pelos valores especificados em argumentos adicionais subsequentes e formatados conforme solicitado. Referência: https://cplusplus.com/reference/cstdio/printf/Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { AsyncResponseStream* response = request->beginResponseStream("text/html"); response->print("<html>"); response->print("<head> "); response->print("<meta charset='utf-8'/>"); response->print("</head>"); response->print("<body>"); response->print("<h1>"); response->printf("Olá %s",request->client()->remoteIP().toString().c_str()); response->print("</h1>"); response->print("<p>"); response->print("Parágrafo aqui."); response->print("</p>"); response->print("</body>"); response->print("<html>"); //envie a resposta por último request->send(response); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
O seguinte algoritmo responde à solicitação do cliente enviando-lhe uma página com conteúdo JSON:
#include "AsyncJson.h" #include "ArduinoJson.h" // ... AsyncResponseStream* response = request->beginResponseStream("application/json"); DynamicJsonDocument doc(1024); doc["heap"] = ESP.getFreeHeap(); doc["ssid"] = WiFi.SSID(); serializeJson(doc, *response); request->send(response);
Onde, na função beginResponseStream()
, há os seguintes parâmetros:
const String& contentType
: Tipo de mídia da Internet (Media type). Neste caso, o tipo é Formato JSON. Acesse, neste link, a lista de MIME types;size_t bufferSize=1460
: parâmetro opcional que define o tamanho do buffer do response.a variável doc
, um objeto da classe DynamicJsonDocument
, que é instanciado informando a quantidade de RAM, na heap, a ser alocada para o documento -para saber quanto alocar, use a ferramenta do ArduinoJson, em https://arduinojson.org/v6/assistant– e, por fim, a função serializeJson()
, que serializa o documento JSON para criar um documento reduzido, ou seja, um documento sem espaços ou quebra de linha entre os valores. Esta função tem os seguintes parâmetros:
JsonDocument
: o documento JSON;output
: o buffer de destino para onde que o documento JSON deve ser passado (no caso deste algoritmo, o response);NOTA: O modo como foi construído este JSON segue o novo padrão da biblioteca Arduino JSON versão 6. Deseja mais informações sobre a migração do padrão Arduino JSON versão 5 para Arduino JSON versão 6? Consulte a documentação em https://arduinojson.org/v6/doc/upgrade/.
Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include "AsyncJson.h" #include "ArduinoJson.h" // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { AsyncResponseStream* response = request->beginResponseStream("application/json"); DynamicJsonDocument doc(1024); doc["heap"] = ESP.getFreeHeap(); doc["ssid"] = "Rede_De_Testes"; serializeJson(doc, *response); request->send(response); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
No algoritmo acima, deve-se estar instalado a biblioteca ArduinoJson. Para instalação, pesquise-a no gerenciador de bibliotecas e a instale.
Resultado:
O seguinte algoritmo mostra, na Serial, todos os cabeçalhos HTTP da requisição do cliente:
//Listar todos os cabeçalhos coletados int headers = request->headers(); // cabeçalhos int i; // índice for (i = 0; i < headers; i++) { AsyncWebHeader* h = request->getHeader(i); // pega o cabeçalho do índice informado Serial.printf("Cabeçalho[%s]: %s\n", h->name().c_str(), // O nome do cabeçalho h->value().c_str()); // O valor do cabeçalho }
Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { //Listar todos os cabeçalhos coletados int headers = request->headers(); // cabeçalhos int i; // índice for (i = 0; i < headers; i++) { AsyncWebHeader* h = request->getHeader(i); // pega o cabeçalho do índice informado Serial.printf("Cabeçalho[%s]: %s\n", h->name().c_str(), // O nome do cabeçalho h->value().c_str()); // O valor do cabeçalho } }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
Ao acessar IP_DO_ESP32/
no navegador web, no monitor serial, é mostrado:
O seguinte algoritmo mostra, na Serial, um cabeçalho HTTP específico, obtido pelo nome, da requisição do cliente:
//obter cabeçalho específico por nome if (request->hasHeader("Host")) // se tem o cabeçalho com o nome "teste", ... { AsyncWebHeader* h = request->getHeader("Host"); // pega o cabeçalho pelo nome informado informado Serial.printf("Host: %s \n", h->value().c_str()); // O valor do cabeçalho }
Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { //obter cabeçalho específico por nome if (request->hasHeader("teste")) // se tem o cabeçalho com o nome "teste", ... { AsyncWebHeader* h = request->getHeader("teste"); // pega o cabeçalho pelo nome informado informado Serial.printf("teste: %s \n", h->value().c_str()); // O valor do cabeçalho } }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
Ao acessar o IP no navegador web, no monitor serial, é mostrado:
O seguinte algoritmo mostra, na Serial, todos os parâmetros HTTP (seja eles POST, FILE ou GET), da requisição do cliente:
// Listar todos os parâmetros int params = request->params(); // parâmetros int i; // índice for (i = 0; i < params; i++){ AsyncWebParameter* p = request->getParam(i); // pega o cabeçalho do índice informado if (p->isFile()) // se parâmetro for um arquivo, ... { Serial.printf("FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); } else if (p->isPost()) // senão, se parâmetro for do tipo POST, ... { Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); } else // senão, parâmetro é do tipo GET, ... { Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } }
Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); // disponibiliza o url "/" server.on("/", HTTP_ANY, [](AsyncWebServerRequest* request) { // Listar todos os parâmetros int params = request->params(); // parâmetros int i; // índice for (i = 0; i < params; i++){ AsyncWebParameter* p = request->getParam(i); // pega o cabeçalho do índice informado if (p->isFile()) // se parâmetro for um arquivo, ... { Serial.printf("FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); } else if (p->isPost()) // senão, se parâmetro for do tipo POST, ... { Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); } else // senão, parâmetro é do tipo GET, ... { Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } } String html = R"====( <html> <head> <meta charset = "utf-8"> <script> function imprimeNaSerial() { var xhr = new XMLHttpRequest(); xhr.open("POST", '/', true); // inicializa uma nova requisição, ou reinicializa uma requisição já existente. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // define o valor do cabeçalho de uma requisição HTTP xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { // Typical action to be performed when the document is ready: alert("Requisição enviada com sucesso"); }else if(this.readyState == 4 && this.status != 200){ alert("Requisição não foi enviada, pois houve alguma falha"); } }; xhr.send("parametro1=123&outro-paramentro=xyz"); // envia uma requisição para o servidor. } </script> </head> <body> <h1>Teste com ESP32</h1> <p> Clique no botão abaixo e imprima na Serial dois Parâmetros POST (parametro1 com valor 123 e outro-parametro com valor xyz): </p> <button onclick="imprimeNaSerial()"> Imprimir Parâmetros POST na Serial</button> </body> </html> )===="; request->send(200,"text/html",html); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
Descrição do Resultado:
IP_DO_ESP32/?teste=113abc
no navegador, no monitor Serial, é mostrado: IP_DO_ESP32/
no navegador e clicar no botão Imprimir Parâmetros POST na Serial, é acionada a função imprimeNaSerial()
, da página HTML, que envia os parâmetros POST ao web server do ESP32. No monitor Serial, é mostrado:O seguinte algoritmo mostra, na Serial, se um determinado parâmetro HTTP GET específico, obtido pelo nome, existe, ou não, através da requisição do cliente:
// Verifique se o parâmetro GET existe ou não if (request->hasParam("nome-qualquer")) { AsyncWebParameter* p = request->getParam("nome-qualquer"); Serial.printf("O parâmetro GET %s existe e possui o valor %s\n", p->name().c_str(), p->value().c_str()); }else{ Serial.print("O parâmetro GET nome-qualquer não existe nesta requisição\n"); }
Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); // disponibiliza o url "/" server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { // Verifique se o parâmetro GET existe ou não if (request->hasParam("nome-qualquer")) { AsyncWebParameter* p = request->getParam("nome-qualquer"); Serial.printf("O parâmetro GET %s existe e possui o valor %s\n", p->name().c_str(), p->value().c_str()); }else{ Serial.print("O parâmetro GET nome-qualquer não existe nesta requisição\n"); } }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Resultado:
IP_DO_ESP32/?nome-qualquer=valor-qualquer
no navegador, no monitor Serial, é mostrado: IP_DO_ESP32/
no navegador, no monitor Serial, é mostrado: O seguinte algoritmo mostra, na Serial, se um determinado parâmetro HTTP POST específico, obtido pelo nome, existe ou não através da requisição do cliente:
// Verifique se o parâmetro POST existe ou não if (request->hasParam("nome-qualquer",true)) { AsyncWebParameter* p = request->getParam("nome-qualquer", true); Serial.printf("O parâmetro POST %s existe e possui o valor %s\n", p->name().c_str(), p->value().c_str()); }else{ Serial.print("O parâmetro POST nome-qualquer não existe nesta requisição\n"); }
Exemplo de uso:
// Inclusão das bibliotecas #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Instanciação do objeto da classe AsyncWebServer AsyncWebServer server(80); // Constantes das credenciais do WiFi const char* ssid = "<SSID>"; const char* password = "<SENHA>"; void setup() { // Conecta-se ao Ponto de acesso com as credenciais fornecidas WiFi.begin(ssid, password); Serial.begin(115200); // disponibiliza o url "/" por acesso somente via POST server.on("/", HTTP_POST, [](AsyncWebServerRequest * request) { // Verifique se o parâmetro POST existe ou não if (request->hasParam("nome-qualquer", true)) { AsyncWebParameter* p = request->getParam("nome-qualquer", true); Serial.printf("O parâmetro POST %s existe e possui o valor %s\n", p->name().c_str(), p->value().c_str()); } else { Serial.print("O parâmetro POST nome-qualquer não existe nesta requisição\n"); } request->send(200); }); // disponibiliza o url "/" por acesso somente via GET server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { String html = R"====( <html> <head> <meta charset = "utf-8"> <script> function imprimeNaSerial() // função, que quando clicar no botão, será enviado uma requisição POST para o server { var xhr = new XMLHttpRequest(); xhr.open("POST", '/', true); // inicializa uma nova requisição, ou reinicializa uma requisição já existente. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // define o valor do cabeçalho de uma requisição HTTP xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { // Typical action to be performed when the document is ready: alert("Requisição enviada com sucesso"); }else if(this.readyState == 4 && this.status != 200){ alert("Requisição não foi enviada, pois houve alguma falha"); } }; xhr.send("nome-qualquer=valor-qualquer"); // envia uma requisição para o servidor. } </script> </head> <body> <h1>Teste com ESP32</h1> <p> Clique no botão abaixo e imprima na Serial a verificação se um Parâmetro POST (nome-qualquer com valor valor-qualquer) existe ou não: </p> <button onclick="imprimeNaSerial()"> Imprimir Parâmetros POST na Serial</button> </body> </html> )===="; request->send(200, "text/html", html); }); // Servidor começa à ouvir os clientes server.begin(); } void loop() {}
Neste algoritmo, o ESP32 disponibiliza o URL “/” para acessos somente via post (configurado por meio de HTTP_POST) e, também, disponibiliza o URL “/” para acessos somente via get (configurado por meio de HTTP_GET). Os dois URL’s não se sobrepõem, pois são disponibilizados com dois métodos HTTP diferentes. Ainda existe outra configuração possível, a HTTP_ANY: este método recebe solicitações do cliente tanto via GET quanto POST no mesmo callback.
Resultado:
Descrição do Resultado:
IP_DO_ESP32/
no navegador e clicar no botão Imprimir Parâmetros POST na Serial, é acionada a função imprimeNaSerial()
, da página HTML, que envia um parâmetro POST ao web server do ESP32. No monitor Serial, é mostrado: Para executar o projeto deste post, é utilizado somente o hardware das demonstrações anteriores:
Clique na imagem abaixo, faça o download do sketch e do diretório data para SPIFFS e, em seguida, faça o upload deles para a placa ESP32:
Para orientações de como fazer o upload do diretório data para o SPIFFS do ESP32, consulte o post SPIFFS: Armazenamento de Arquivos do ESP32, aqui mesmo, no blog Eletrogate.
Ao ser acessada a página /
do ESP32 no navegador web, ele o redireciona para a página /index.html
. Na página /index.html
, é mostrada a lista de redes WiFi juntamente com o nível RSSI do WiFi. Também é disponibilizado a opção mais dados para cada rede WiFi, em que é possível os dados de BSSID (endereço MAC do ponto de acesso), de Canal do WiFi e de Tipo de encriptação do WiFi. A cada 10 segundos, automaticamente é atualizada, assincronamente, a lista das redes disponíveis. Caso o usuário deseje, é possível atualizar a lista de redes WiFi manualmente.
Veja, no vídeo abaixo, a demonstração de funcionamento do projeto:
Curtiu o post? Avalie e deixe um comentário! Siga-nos também no Instagram e nos marque quando fizer algum projeto nosso: @eletrogate. Até a próxima!
Tenha a Metodologia Eletrogate na sua Escola! Conheça nosso Programa de Robótica Educacional.
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!