ESP32 - SERVIDOR WEB
WiFi.begin(ssid, password = null, channel = 0, bssid = null, connect = true)
- ssid, nombre de la red WiFi a la que nos queremos conectar (max 32 char)
- password, opcional, contraseña (mínimo 8 char y máximo 64)
- channel, opcional, el canal de WiFi a emplear
- bssid, opcional, dirección MAC del punto de acceso
- connect, indica si queremos conectar inmediatamente (si es false, sólo guarda los parámetros)
#include <WiFi.h>
const char* ssid = "ssid";
const char* password = "password";
void setup()
{
Serial.begin(115200);
delay(10);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Conectando a:\t");
Serial.println(ssid);
while (WiFi.status() != WL_CONNECTED)
{
delay(200);
Serial.print('NO HAY CONEXION');
}
// DATOS DE LA RED
Serial.println();
Serial.print("Conectado a:\t");
Serial.println(WiFi.SSID());
Serial.print("IP address:\t");
Serial.println(WiFi.localIP());
}
void loop()
{
}
La función WiFi.begin(…) del ESP guarda los credenciales indicados en la memoria flash no volátil (que se mantiene incluso aunque carguemos otro programa).
Las funciones WiFi.begin(…) devuelven el estado del ESP para determinar cuándo hemos establecido la conexión con la red. También podemos obtenerlo en otro momento a lo largo de nuestro programa con la función WiFi.status(). Esta variable de estado del ESP puede ser:
WL_CONNECTED | Conexión establecida |
---|---|
WL_NO_SSID_AVAIL | El SSID no se encuentra |
WL_CONNECT_FAILED | Contraseña incorrecta |
WL_IDLE_STATUS | Wi-Fi está cambiando entre estados |
WL_DISCONNECTED | El ESP8266 no está configurado en modo STA |
La función WiFi.mode(WIFI_STA) es opcional en este ejemplo. Sirve para dejar únicamente el modo STA y desactivar el AP en caso de que lo hubiéramos configurado previamente ya que, como decíamos, el ESP guarda la configuración del WiFi aunque lo reprogramemos. Las opciones de modos son:
WIFI_OFF | Apagado |
---|---|
WIFI_STA | Estacion |
WIFI_AP | Access point |
WIFI_AP_STA | Station+Acces Point |
Cuando el codigo se hace muy largo es mejor dividirlo en varios ficheros. En este ejemplo se puede crear un fichero dentro del mismo directorio del codigo para almacenar las funciones.
void ConnectWiFi_STA()
{
Serial.println("");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(100);
Serial.print('NO HAY CONEXION');
}
Serial.println("");
Serial.print("Iniciado STA:\t");
Serial.println(ssid);
Serial.print("IP address:\t");
Serial.println(WiFi.localIP());
}
Para luego llamarlo dentro del codigo de arduino:
#include <WiFi.h>
#include "data.h" // tengo definido el ssid y el password
#include "EMA_Utils.hpp"
void setup()
{
Serial.begin(115200);
ConnectWiFi_STA();
}
void loop()
{
}
MULTIPLE REDES WIFI
Existe otra forma de conectarse a una red WiFi, o mejor dicho, a la que tenga mejor señal. Para ello se puede usar la librería WiFiMulti.
En la configuración usare wifiMulti.addAP(…) para agregar varias redes WiFI proporcionando sus respectivas SSID y su contraseña. Al arrancar, el ESP se conectará a la red que tenga mejor recepción.
Sin embargo, gestionar un WiFi múltiple también supone una sobrecarga de trabajo adicional para el ESP, aunque no demasiado grande. Por lo que usar esta función únicamente cuando realmente sea necesaria. usarla “porque si”.
#include <WiFi.h>
#include <WiFiMulti.h>
ESP8266WiFiMulti wifiMulti;
void setup()
{
Serial.begin(115200);
delay(10);
WiFi.mode(WIFI_STA);
wifiMulti.addAP("ssid 1", "password 1");
wifiMulti.addAP("ssid 2", "password 2");
wifiMulti.addAP("ssid 3", "password 3");
Serial.println("Conectando");
while (wifiMulti.run() != WL_CONNECTED)
{
delay(250);
Serial.print('NO HAY CONEXION');
}
Serial.println();
Serial.print("Conectado a:\t");
Serial.println(WiFi.SSID());
Serial.print("IP address:\t");
Serial.println(WiFi.localIP());
}
void loop()
{
}
FUNCIONES WIFI DEL ESP
Aquí tenemos un resumen de algunas de las funciones adicionales disponibles en ESP WiFi.
// Gestión de la conexión
WiFi.reconnect();
WiFi.disconnect(true);
WiFi.isConnected();
WiFi.setAutoConnect(autoConnect);
WiFi.status();
// Devuelven el valor indicado (no sirven para reescribir el valor)
WiFi.SSID();
WiFi.hostname();
WiFi.localIP();
WiFi.subnetMask()
WiFi.gatewayIP();
WiFi.dnsIP(dns_no);
WiFi.macAddress();
ENCENDER LED
#include <WiFi.h> // Añade ibreria
#define LED 2 // Indica pin que se usará (D2)
#include "data.h"
String p="off"; // dato de apagado del led
// Crea servidor llamado "server" y establece el puerto 80 para acceder
WiFiServer server(80);
void setup() {
//Configura D2 como salida y lo pone en un estado bajo (0)
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
//Inicia puerto serial a velocidad de 115200 baudios
Serial.begin(115200);
Serial.println();
Serial.println("Configurando");
// Inicia conexión WiFi con las datos de la red especificados
WiFi.begin(ssid1, password1); //configurando las credenciales
/**
Este ciclo imprime un punto tras otro mientras no se establezca conexión.
**/
Serial.print("Conectandome");
while (WiFi.status() != WL_CONNECTED) // Espera conexión a la red
{
delay(500);
Serial.print("."); // Imprime puntos
}
Serial.println();
Serial.print("Conectado, La dirección IP es: ");
Serial.println(WiFi.localIP()); // Imprime la IP del ESP32
server.begin(); // Inicia el servidor
Serial.println("Servidor iniciado");
}
void loop() {
/**
Empezamos creando un cliente al que se nombrará client. Un cliente será cualquier dispositivo de la red que entré a la dirección del ESP32.
**/
WiFiClient client = server.available(); // Recibe las conexciones de clientes
/**
Se crea una condición en la que si el cliente se a conectado se avise mediante el monitor serial. Además se crea una variable llamada currentLine que usare después.
**/
if (client) { // Si hay un cliente
Serial.println("Nuevo cliente."); // Indica el acceso de un cliente
String currentLine = ""; // Variable para datos de fin de linea
/**
Usaremos un ciclo while. Mientras el cliente esté conectado (connected) y haya datos (available)
se guardarán los datos en una variable char llamada c y se imprimiran esos datos leídos del cliente.
**/
while (client.connected()) { // Cliente conectado
if (client.available()) { // Datos disponibles para ser leido
char c = client.read(); // Lectura de byte en variable C
Serial.write(c); // Muestra los datos
/**
Se crean unas condiciones en las que se toma en cuenta si el dato leído es un salto de línea (\n)
y la longitud del valor (length) de currentLine es igual a 0 para que se cumplan.
**/
if (c == '\n') { // Si el byte es un caracter de nuevo salto de linea
if (currentLine.length() == 0) { // Si no hay caracteres, entonces lanza el codgo HTML
/**
Si las condiciones anteriores se cumplen se despliega el sitio web desde el ESP32 hacia el cliente en formato HTML.
Para ello se llama a client y se le da la instrucción println para imrpimir el HTML una línea a la vez.
La parte que se está viendo corresponde a los parámetros y cabecera (head) de un documento HTML. Dentro de la cabecera
se indican datos que no se suelen visualizar al navegar en la página. Por ejemplo, los estilos (style) CSS de los botones (.button) que se usarán después.
**/
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
client.println("<style>html{font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button {border: none;color: white;padding: 15px 32px; text-align: center;");
client.println("text-decoration: none;display: inline-block;font-size: 16px; margin: 4px 2px;cursor: pointer;}");
client.println(".button1 {background-color: #4CAF50;} /* Green */");
client.println(".button2 {background-color: #008CBA;} /* Blue */");
client.println("</style></head>");
// Creación de botones
/**
se procede a crear el cuerpo (body) de la página. Se muestra un título usando la etiqueta H1.
Después usando la variable de estado llamada "p" se decide el texto y estilo que tendrá le botón para encender o apagar el led.
Recordemos que la variable tenía el valor “off” y programamos el led para que empiece estando apagado. Por ello se mostrará
el botón con el texto “ENCENDER” para indicarnos que esa será la acción que podremos realizar.
Siguiendo con el botón “ENCENDER” hay que mencionar que al hacer clic (onClick) sobre él nos llevará a la dirección “/LED-ON”
(location.href). Este cambio será visible en la URL.
**/
client.print("<body><h1>WebServer con ESP32</h1>");
if(p=="off"){
client.println("<button type='button' class='button button1' onClick=location.href='/LED=ON'> ENCENDER </button><br><br>");
}
else{
client.println("<button type='button' class='button button2' onClick=location.href='/LED=OFF'> APAGAR </button><br><br>");
}
client.print("</body></html>");
client.println();
// Rompe el codigo del while-loop
break;
}
/**
En caso de que la longitud del valor de la variable currentLine no sea 0 se procede a asignarle un valor vacío.
**/
else { // Limpiando variable
currentLine = "";
}
}
else if (c != '\r') { // Si no hay retorno de carro
currentLine += c; // agrega al final de la linea
}
/**
La siguiente sección del código busca dentro de currentLine las direcciones que obtenemos al hacer
clic en el botón de la página y modifica el estado del led de acuerdo a ello.
Por ejemplo. Si dentro hallamos “GET /LED=ON” quiere decir que presionamos el botón “ENCENDER”.
En consecuencia, el pin del led se activará (HIGH) y la variable p cambiará a “on”.
Recuerda que en el código hay una sección que toma en cuenta el valor de p. En este caso al tener “on”
el texto del botón será “APAGAR” y al hacer clic sobre él nos dirigirá a la dirección “/LED=ON”. Y así sucesivamente mientras se use el botón.
**/
// Revisando el datos recibido del url
if (currentLine.indexOf("GET /LED=ON") != -1) { // si esta ok ineOf -> return un valor mayor a 0
digitalWrite(LED, HIGH); // GET /LED=ON
p="on";
}
if (currentLine.indexOf("GET /LED=OFF") != -1) {
digitalWrite(LED, LOW); // GET /LED=OFF
p="off";
}
}
}
/**
Finalmente se cierra la conexión con el cliente.
**/
// cerrando la conexión
client.stop();
Serial.println("Cliente Desconectado");
}
}