History: 3. Servidor Web control de un LED

Revision made 7 years ago by Jaime Laborda. Go to the last revision.

Una vez hemos configurado el Arduino para que nos programe correctamente la placa pasamos a hacer nuestro primer ejemplo de IoT.

En este primer ejemplo vamos a controlar el LED interno de la NodeMCU mediante una página web HTTP. Para ello vamos a crear un servidor web con el ESP8266 al que nos conectaremos con el ordenador como cliente. Mediante dos botones realizaremos peticiones al servidor para que encienda o apague el LED.

Es el ejemplo más sencillo que se puede realizar después del Blink y con él aprenderemos a conectarnos a una red Wifi, a crear un servidor HTTP, y a responder y diferenciar entre las distintas peticiones que nos hará un cliente.

1. Conexión a red WiFi

El primer paso es conectarnos a una red WiFi. La librería que usaremos para controlar el ESP8266 mediante Arduino ya integra las funciones correspondientes para conectarnos por WiFi. La librería del ESP8266 en Arduino ofrece una API muy semejante, por no decir que es exactamente igual, a la que ofrece Arduino con su shield y la librería WiFi.h.

En este caso, la librería es la ESP8266Wifi.h

Las funciones importantes que debemos usar para conectarnos al WiFi desde Arduino serán las siguientes:

  • WiFi.begin("network-name", "pass-to-network"): Nos permite iniciar una conexión. Acepta como parámetros la SSID y el PASS del WiFi.
  • WiFi.mode(m): Establece el modo de operación del WiFi (WIFI_AP, WIFI_STA, WIFI_AP_STA o WIFI_OFF)
  • WiFi.status(): Devolverá el parámetro WL_CONNECTED si estamos conectados correctamente.
  • WiFi.localIP(): Nos devuelve la IP a la que estamos conectados. (Solo para STA)

Conociendo estas dos funciones estamos listos para conectar nuestro ESP8266 mediante el siguiente sketch de código propuesto. En el utilizaremos la consola seríe para conectarnos a una red wifi en modo STA (stación) y una vez conectados, pondremos la IP que nos ha asignado el router, la cual nos servirá como dirección para identificar al dispositivo.

En este caso estamos utilizando el ESP8266 para conectarnos a una red WiFi, pero también podríamos generar una red desde el propio ESP8266 configurando la red en modo AP (Access Point). No obstante, esto no nos interesa para el propósito de este taller y solo usaremos el chip en modo estación (STA).

#include <ESP8266WiFi.h>

void setup()
{
  Serial.begin(115200);
  Serial.println();

  WiFi.begin("network-name", "pass-to-network");
  
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  
  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {}
  • Compilamos el código y lo subimos a la placa. Si todo esta correcto deberíamos ver el siguiente mensaje en la consola serie.
  • Recuerda configurar el monitor serie de Arduino a 115200 baudios.

Connecting...... Connected, IP address: 192.168.1.XX

2. Ejemplo: Control de un LED por WiFi

Una vez conectados al WiFi, ya estamos preparados para hacer cosas divertidas. Lo primero que haremos será crear un pequeño servidor web HTTP en el NodeMCU para encender o apagar el LED que incluye la placa mediante dos botones que realizarán peticiones al servidor.

Para ello, haremos que nuestro NodeMCU se convierta en un pequeño servidor web listo para atender a peticiones HTTP de clientes que se conecten a el. Esto lo haremos creando un objeto WifiServer en el puerto 80 y posteriormente lo inicializaremos con un begin()

 WifiServer server(80);
server.begin();

Esto nos asignará un IP local y nos permitirá conectarnos al ESP8266 desde otros dispositivos (por ahora, siempre que estén conectados a la misma red local).

El resto de código es auto-explicativo:

#include <ESP8266WiFi.h> //Incluimos la librería para del WiFi
 
//Credenciales del WiFi
const char* ssid = "INSERTAR WIFI_SSID";
const char* password = "INSERTAR PASSWORD";
 
int ledPin = D0; // D0 is the LEDBUILDIN (Active LOW)
WiFiServer server(80);
 
void setup() {
  Serial.begin(115200); //Inicio el puerto serie 
  delay(10);
 
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
 
  // Conecto con la red WiFi en modo estación (STA)
  Serial.println();
  Serial.println();
  Serial.print("Conectando a ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi conectado");
 
  // Inicializo el servidor
  server.begin();
  Serial.println("Servidor iniciado");
 
  // Muestro la IP local asignada. URL del servidor
  Serial.print("Usa esta URL para conectar al servidor: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");
 
}
 
void loop() {
  // Compruebo si hay un cliente disponible (una petición)
  WiFiClient client = server.available();
  if (!client) {
    return; // En caso de no haber un cliente, no hago nada
  }
 
  // Espero hasta que el cliente realice una petición
  Serial.println("¡Nuevo cliente!");
  while(!client.available()){
    delay(1);
  }
 
  // Leo la primera linea de la petición del cliente
  String request = client.readStringUntil('\r'); // Leo hasta retorno de carro
  Serial.println(request); //Imprimo la petición
  client.flush(); //Limpio el buffer
 
  // Interpreto lo que he recibido
 
  int value = LOW;
  if (request.indexOf("/LED=ON") != -1)  {
    digitalWrite(ledPin, HIGH);
    value = HIGH;
  }
  if (request.indexOf("/LED=OFF") != -1)  {
    digitalWrite(ledPin, LOW);
    value = LOW;
  }
 
// Pongo ledPin al valor que ha solicitado el cliente en la petición
 
  // Devuelvo la respuesta al cliente -> Todo ha ido bien, el mensaje ha sido interpretado correctamente
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); //  do not forget this one
  
  // A partir de aquí creo la página en raw HTML
  client.println("<!DOCTYPE HTML>"); 
  client.println("<html>");
 
  client.print("El LED está:  ");
 
  if(value == HIGH) {
    client.print("ON");
  } else {
    client.print("OFF");
  }
  client.println("<br><br>");
  client.println("<a href=\"/LED=ON\"\"><button>Encender </button></a>"); // Los botones con enlace
  client.println("<a href=\"/LED=OFF\"\"><button>Apagar </button></a><br />");  
  client.println("</html>");
 
  delay(1);
  Serial.println("Cliente desconectado"); // Nos desconectamos del cliente
  Serial.println("");
 
}

El ejemplo lo puedes descargar en la parte de código del github del proyecto.

  • Si has subido el código a la placa, te habrás dado cuenta que al pulsar el botón Encender el LED se apaga, y al pulsar el botón Apagar el LED se enciende... ¿Por que va al revés? ¿Lo hemos hecho mal?...

El LED_BUILTIN de la placa NodeMCU es activo a nivel bajo, es decir, para activarlo debemos poner el pin a LOW.

digitalWrite(D0, HIGH); // Apaga el LED
digitalWrite(D0, LOW);  // Enciende el LED

Esto sucede porque el LED está conectado de la siguiente manera:

3. Ejercicios

  • Ejercicio 1: Se propone como ejercicio modificar el código para que funcione de manera correcta, es decir, de manera lógica.
  • Ejercicio 2: Conecta un LED externo con una resistencia de 160-330 Ohms a otro pin y modifica el código para encender/apagar desde el navegador dicho LED.
  • Ejercicio 3: Añade 2 LEDs y modifica el código para que el servidor muestre al usuario 4 botones y poder encender/apagar independientemente uno u otro.

4. Ejercicio avanzado: Control PWM LED por WiFi

Se propone como ejercicio práctico complementario mostrar una interfaz web capaz de cambiar el valor PWM de un LED.

La técnica de PWM (Pulse Width Modulation) nos permite emular una salida analógica por un pin de Arduino para, por ejemplo, cambiar la intensidad con la que brilla un LED desde apagado hasta totalmente encendido.

Para cambiar la modulación por ancho de pulso usaremos la función analogWrite(PIN, DUTY_CYCLE), donde DUTY_CYCLE puede tomar un valor entre 0 y 255 (resolución de 8 bits).

analogWrite(D5, 128);

Debes investigar que pines de la NodeMCU están preparados para PWM, ya que, al igual que en Arduino, no todos lo son.

La interfaz web deberá incluir un elemento edit que le permita al usuario establecer un valor de ciclo de trabajo determinado.